Compare commits

..

20 Commits
17425 ... 17455

Author SHA1 Message Date
Martin Molinero
8897164794 Speed loading improvements 2026-01-05 16:49:42 -03:00
Martin-Molinero
a66f279852 Fix some incorrect future expirations (#9184)
- Some future expiry functions were missing to account for holidays,
  adding unit test reproducing issue
2026-01-02 12:58:29 -03:00
Martin-Molinero
6575b57146 Fix future expiration year calculation (#9182) 2026-01-02 10:21:02 -03:00
yyxxddjj
3fa700e450 New Feature: Implement Covariance Indicator #6982 (#9144)
* Implements Covariance as Lean Indicator

* Add COV helper method and fix AcceptsVolumeRenkoBarsAsInput test

* Fix AcceptsRenkoBarsAsInput test to use smaller period for faster execution

* Fix slow Renko tests by limiting data processed to 50 rows
2025-12-31 16:02:03 -03:00
Adalyat Nazirov
7735917c83 Prioritize CryptoFuture data feeds for dYdX (#9178)
* Prioritize CryptoFuture data feeds for dYdX

* revert changes for existing crypto subscriptions

* use Concat instead of adding into list
2025-12-31 13:19:58 -03:00
Jhonathan Abreu
67489eef57 Add GetInt64 StreamReader extension method (#9177)
* Add GetInt64 StreamReader extension method

* Minor change

* Cleanup

* Add unit tests
2025-12-31 11:58:51 -04:00
JosueNina
241306275a Replace external dataset with mock data in sweetviz test (#9176) 2025-12-31 12:18:22 -03:00
Ricardo Andrés Marino Rojas
773bd53525 Add 2026 CME Future & HKFE Holidays, early closes, late opens and bank holidays (#9174)
* Add 2026 HKFE Future holidays & early closes

* rebase Add 2026 Future-cme-equity Holidays, Early closes, late opens

* Add (again) HKFE 2026 Holidays and early closes

* Add Future-cme-interest 2026 holidays

* Add 2026 CME Fx 2026 holidays"

- Add 2026 CME Fx holidays, early closes, late opens, bank holidays
- Exclude CNH, MNH and MIR as they expire rules don't consider US
  Holidays
- Fix wrong early close on 12/24/2025 from 12:15 to 12:45

* Add CME Future crypto 2026 Holidays, EC, LO & BH

* Add CME Future Energy 2026 holidays, EC, LO, BH

* Add CME Futures metals holidays, ec, lo, bh

* Add CME Futures grains 2026 holidays, ec, lo, bh

* Add CME Futures Dairy 2026 holidays, ec, lo, bh

* Add CME Futures livestock holidays, ec, lo, bh

* Add CME Future Lumber holidays, ec, lo, bh

* Add CME Futures Softs holidays, ec, lo, bh

* Add CME Futures Oilseeds holidays, ec, lo, bh

* Add CME Futures AW, GD Holidays, EC, LO and BH

* Move repeated bank holidays to generic entries

* Nit change

* Solve bug

Since 11/26/2026 is a bank holiday for CME energy futures, the expiry
date is moved to 11/25/2026 as the expiry date for HH is the third last
business day of the month prior to the contract month
2025-12-31 11:33:59 -03:00
JosueNina
0854ab82da Default option filter now includes weeklies to prevent empty chains (#9162)
* Return weekly contracts if no standard contracts exist

* Fix unit and regression tests

* Centralize default expiration type flags

* Add ExcludeWeeklys() method

* Mark IncludeWeeklys() as obsolete since weeklies are now default
2025-12-31 10:11:46 -03:00
JosueNina
2c0390fde3 Change Config.Get logging from Trace to Debug level (#9171)
* Change Config.Get logs from Trace to Debug level to reduce noise

* Wrap Config.Get logs with DebuggingEnabled check
2025-12-31 10:09:37 -03:00
JosueNina
32fcd94abc Exclude Period property from WindowIndicator (#9172) 2025-12-31 10:08:37 -03:00
Martin-Molinero
090ffebd03 Minor ApiConnection improvement (#9173) 2025-12-30 18:48:27 -03:00
JosueNina
914d0810af Make Collaborator.Uid nullable to fix JSON deserialization error (#9170) 2025-12-30 15:40:22 -03:00
Martin-Molinero
10902f95dd net10 fix: Update clr-loader (#9166) 2025-12-29 19:07:35 -03:00
Martin-Molinero
2e67b9ad4f Feature net10 update (#9161)
* Feature update to net10

* Update to net10

* Update pythonnet to 2.0.51

* Remove dotnet config

* Remove net9

* Minor cleanup
2025-12-29 09:53:37 -03:00
Ricardo Andrés Marino Rojas
7adf27aa61 Add 2026 CME Future Holidays, EC, LP, BH (#9163)
- Add 2026 CME Future Holidays, Early closes, Late opens and bank holidays
- Exclude MIR, CNH, MNH as they expire rules don't follow US holidays
2025-12-27 10:52:23 -03:00
Martin-Molinero
7ea0f60905 Add SGX futures holidays (#9160) 2025-12-26 15:24:55 -03:00
Martin-Molinero
d9c71e3d34 Adding Forex-Oanda & Cfd-IB 2026 new years holiday. Removing duplication (#9159) 2025-12-26 12:10:19 -03:00
Martin-Molinero
b040518d52 Minor foundation update reverts (#9156) 2025-12-24 17:02:49 -03:00
Roman Yavnikov
725737610a fix: several Futures Currencies: 6B, 6M, 6J, 6E, 6C (#9155) 2025-12-24 17:39:50 +02:00
108 changed files with 15198 additions and 2038 deletions

View File

@@ -28,9 +28,9 @@ jobs:
shell: bash
run: |
# install dependencies
pip3 install papermill==2.4.0 clr-loader==0.1.6
pip3 install papermill==2.4.0 clr-loader==0.2.9
# install kernel
dotnet tool install --global Microsoft.dotnet-interactive --version 1.0.607001
dotnet tool install -g --no-cache --version 1.0.661703 --add-source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" Microsoft.dotnet-interactive
# Add dotnet tools to Path
export PATH="$HOME/.dotnet/tools:$PATH"
# activate kernel for jupyter

View File

@@ -96,7 +96,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 1658168;
public long DataPoints => 2349547;
/// <summary>
/// Data Points count of the algorithm history

View File

@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180));
@@ -73,7 +73,7 @@ namespace QuantConnect.Algorithm.CSharp
var higherStrike = callContracts[2].Strike;
var optionStrategy = OptionStrategies.CallButterfly(_optionSymbol, higherStrike, middleStrike, lowerStrike, expiry);
Order(optionStrategy, 10);
}
}

View File

@@ -50,8 +50,9 @@ namespace QuantConnect.Algorithm.CSharp
// set our strike/expiry filter for this option chain
// SetFilter method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
option.SetFilter(-2, +2, 0, 180);
// option.SetFilter(-2, +2, TimeSpan.Zero, TimeSpan.FromDays(180));
option.SetFilter(u => u.StandardsOnly()
.Strikes(-2, +2)
.Expiration(0, 180));
// Adding this to reproduce GH issue #2314
SetWarmup(TimeSpan.FromMinutes(1));
@@ -83,7 +84,7 @@ namespace QuantConnect.Algorithm.CSharp
Liquidate();
}
foreach(var kpv in slice.Bars)
foreach (var kpv in slice.Bars)
{
Log($"---> OnData: {Time}, {kpv.Key.Value}, {kpv.Value.Close:0.00}");
}

View File

@@ -48,11 +48,10 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180));
// .Expiration(TimeSpan.Zero, TimeSpan.FromDays(180)));
.Expiration(0, 180)); // .Expiration(TimeSpan.Zero, TimeSpan.FromDays(180)));
// use the underlying equity as the benchmark
SetBenchmark(equity.Symbol);

View File

@@ -48,7 +48,7 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180));

View File

@@ -58,7 +58,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol, fillForward: true);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
.Expiration(0, 180));
}

View File

@@ -47,7 +47,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol, fillForward: true);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
.Expiration(0, 180));
}
@@ -243,8 +243,7 @@ namespace QuantConnect.Algorithm.CSharp
}
if (orderEvent.Quantity != order.Quantity)
{
throw new RegressionTestException($@"OrderEvent quantity should hold the current order Quantity. Got {orderEvent.Quantity
}, expected {order.Quantity}");
throw new RegressionTestException($@"OrderEvent quantity should hold the current order Quantity. Got {orderEvent.Quantity}, expected {order.Quantity}");
}
if (order is ComboLegLimitOrder && orderEvent.LimitPrice == 0)
{
@@ -303,8 +302,7 @@ namespace QuantConnect.Algorithm.CSharp
{
throw new RegressionTestException(
"There were expected 6 filled market orders, 3 filled combo limit orders and 6 filled combo leg limit orders, " +
$@"but there were {filledComboMarketOrders.Count} filled market orders, {filledComboLimitOrders.Count
} filled combo limit orders and {filledComboLegLimitOrders.Count} filled combo leg limit orders");
$@"but there were {filledComboMarketOrders.Count} filled market orders, {filledComboLimitOrders.Count} filled combo limit orders and {filledComboLegLimitOrders.Count} filled combo leg limit orders");
}
if (openOrders.Count != 0 || openOrderTickets.Count != 0)

View File

@@ -43,7 +43,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-1, +1).Expiration(0, 30));
option.SetFilter(u => u.StandardsOnly().Strikes(-1, +1).Expiration(0, 30));
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
@@ -70,7 +70,7 @@ namespace QuantConnect.Algorithm.CSharp
var legs = new List<Leg> { Leg.Create(atmContract.Symbol, -1), Leg.Create(atmContract.Symbol.Underlying, 100) };
var comboPrice = underlyingPrice - optionPrice;
if(comboPrice < 734m)
if (comboPrice < 734m)
{
// just to make sure the price makes sense
throw new RegressionTestException($"Unexpected combo price {comboPrice}");

View File

@@ -40,7 +40,7 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2014, 07, 06);
var option = AddOption("AAPL", Resolution.Daily);
option.SetFilter(-5, +5, 0, 365);
option.SetFilter(u => u.StandardsOnly().Strikes(-5, +5).Expiration(0, 365));
_symbol = option.Symbol;
}

View File

@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption("GOOG");
_optionSymbol = option.Symbol;
option.SetFilter(-2, +2, 0, 180);
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
public override void OnData(Slice slice)

View File

@@ -50,7 +50,7 @@ namespace QuantConnect.Algorithm.CSharp
SetCash(500000);
var option = AddOption("GOOG");
option.SetFilter(universe => universe.Strikes(-3, 3).Expiration(0, 180));
option.SetFilter(universe => universe.StandardsOnly().Strikes(-3, 3).Expiration(0, 180));
_symbol = option.Symbol;
}

View File

@@ -49,7 +49,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption("GOOG");
_optionSymbol = option.Symbol;
option.SetFilter(-2, +2, 0, 180);
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
SetBenchmark("GOOG");
}

View File

@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(UnderlyingTicker);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180 * 3));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180 * 3));
SetBenchmark(equity.Symbol);
}

View File

@@ -47,7 +47,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol);
_optionSymbol = option.Symbol;
option.SetFilter(-2, +2, 0, 180);
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
public override void OnData(Slice slice)

View File

@@ -45,7 +45,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol);
OptionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
protected virtual void OverrideMarginModels()
@@ -75,7 +75,7 @@ namespace QuantConnect.Algorithm.CSharp
.ThenBy(x => x.Strike)
.First();
if(!_placedTrades)
if (!_placedTrades)
{
_placedTrades = true;
PlaceTrades(atmContracts);
@@ -100,7 +100,7 @@ namespace QuantConnect.Algorithm.CSharp
{
throw new RegressionTestException($"Unexpected position group count {Portfolio.Positions.Groups.Count} for symbol {ticket.Symbol} and quantity {ticket.Quantity}");
}
if(Portfolio.TotalMarginUsed != expectedMarginUsed)
if (Portfolio.TotalMarginUsed != expectedMarginUsed)
{
throw new RegressionTestException($"Unexpected margin used {expectedMarginUsed}");
}

View File

@@ -0,0 +1,143 @@
/*
* 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.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Securities.Option;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Verifies that weekly option contracts are included when no standard contracts are available.
/// </summary>
public class OptionChainIncludeWeeklysByDefaultRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Option _option;
private Symbol _optionSymbol;
private int _weeklyCount;
private int _totalCount;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2015, 12, 24);
SetEndDate(2015, 12, 24);
_option = AddOption("GOOG");
_optionSymbol = _option.Symbol;
_option.SetFilter((optionFilter) =>
{
return optionFilter.Strikes(-8, +8).Expiration(0, 0);
});
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
OptionChain chain;
if (slice.OptionChains.TryGetValue(_optionSymbol, out chain))
{
_totalCount += chain.Contracts.Count;
foreach (var contract in chain.Contracts.Values)
{
if (!OptionSymbol.IsStandard(contract.Symbol))
{
_weeklyCount++;
}
}
}
}
public override void OnEndOfAlgorithm()
{
if (_weeklyCount == 0)
{
throw new RegressionTestException("No weekly contracts found");
}
if (_totalCount != _weeklyCount)
{
throw new RegressionTestException("When no standard option expirations are available, the option chain must fall back to weekly contracts only");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 22702;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}

View File

@@ -96,7 +96,7 @@ namespace QuantConnect.Algorithm.CSharp
protected override OptionFilterUniverse Filter(OptionFilterUniverse filter)
{
return filter.BackMonth().Contracts(contracts => contracts.Take(15));
return filter.StandardsOnly().BackMonth().Contracts(contracts => contracts.Take(15));
}
}

View File

@@ -36,7 +36,9 @@ namespace QuantConnect.Algorithm.CSharp
SetStartDate(2014, 06, 05);
SetEndDate(2014, 06, 09);
_aaplOption = AddOption("AAPL").Symbol;
var option = AddOption("AAPL");
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
_aaplOption = option.Symbol;
AddUniverseSelection(new DailyUniverseSelectionModel("MyCustomSelectionModel", time => new[] { "AAPL" }, this));
}

View File

@@ -28,7 +28,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Regression algorithm to test the OptionChainedUniverseSelectionModel class
/// </summary>
public class OptionChainedUniverseSelectionModelRegressionAlgorithm: QCAlgorithm, IRegressionAlgorithmDefinition
public class OptionChainedUniverseSelectionModelRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
public override void Initialize()
{
@@ -39,7 +39,7 @@ namespace QuantConnect.Algorithm.CSharp
var universe = AddUniverse("my-minute-universe-name", time => new List<string> { "AAPL", "TWX" });
AddUniverseSelection(new OptionChainedUniverseSelectionModel(universe, u => u.Strikes(-2, +2)
AddUniverseSelection(new OptionChainedUniverseSelectionModel(universe, u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180)));

View File

@@ -43,7 +43,7 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180));
@@ -83,7 +83,7 @@ namespace QuantConnect.Algorithm.CSharp
spread = security.Price - security.Holdings.AveragePrice;
}
}
else if(security.BidPrice != 0)
else if (security.BidPrice != 0)
{
spread = security.Holdings.AveragePrice - security.Price;
}

View File

@@ -42,7 +42,7 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-1, +1)
option.SetFilter(u => u.StandardsOnly().Strikes(-1, +1)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 60));

View File

@@ -42,7 +42,7 @@ namespace QuantConnect.Algorithm.CSharp
_aapl = AddEquity("AAPL", Resolution.Minute, extendedMarketHours: true, dataNormalizationMode: DataNormalizationMode.Raw).Symbol;
var option = AddOption(_aapl, Resolution.Minute);
option.SetFilter(-1, +1, 0, 365);
option.SetFilter(u => u.StandardsOnly().Strikes(-1, +1).Expiration(0, 365));
}
public override void OnData(Slice slice)

View File

@@ -30,6 +30,8 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2014, 6, 9);
var option = AddOption("AAPL", Resolution.Minute);
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
// BaroneAdesiWhaley model supports American style options
option.PriceModel = OptionPriceModels.BaroneAdesiWhaley();

View File

@@ -29,6 +29,8 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2014, 6, 9);
var option = AddOption("AAPL", Resolution.Minute);
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
// BlackSholes model does not support American style options
option.PriceModel = OptionPriceModels.BlackScholes();

View File

@@ -38,7 +38,7 @@ namespace QuantConnect.Algorithm.CSharp
UniverseSettings.Resolution = Resolution.Daily;
var option = AddOption("GOOG");
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
_optionSymbol = option.Symbol;
if (UniverseManager.TryGetValue(option.Symbol, out var universe)

View File

@@ -42,7 +42,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equitySymbol);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
.Expiration(0, 180));
Portfolio.MarginCallModel = new CustomMarginCallModel(Portfolio, DefaultOrderProperties);

View File

@@ -39,6 +39,7 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2014, 06, 09);
var option = AddOption("AAPL");
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
_optionSymbol = option.Symbol;
var optionContractSymbol = OptionChain(_optionSymbol)

View File

@@ -45,7 +45,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption("GOOG");
_optionSymbol = option.Symbol;
option.SetFilter(-2, +2, 0, 180);
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
SetBenchmark("GOOG");
}
@@ -67,8 +67,7 @@ namespace QuantConnect.Algorithm.CSharp
var buyingPowerModel = positionGroup.BuyingPowerModel as OptionStrategyPositionGroupBuyingPowerModel;
if (buyingPowerModel == null)
{
throw new RegressionTestException($@"Expected position group buying power model type: {nameof(OptionStrategyPositionGroupBuyingPowerModel)
}. Actual: {positionGroup.BuyingPowerModel.GetType()}");
throw new RegressionTestException($@"Expected position group buying power model type: {nameof(OptionStrategyPositionGroupBuyingPowerModel)}. Actual: {positionGroup.BuyingPowerModel.GetType()}");
}
AssertStrategyPositionGroup(positionGroup);
@@ -91,9 +90,7 @@ namespace QuantConnect.Algorithm.CSharp
var ordersCount = Transactions.GetOrders((order) => order.Status == OrderStatus.Filled).Count();
if (ordersCount != ExpectedOrdersCount)
{
throw new RegressionTestException($@"Expected {ExpectedOrdersCount
} orders to have been submitted and filled, half for buying the strategy and the other half for the liquidation. Actual {
ordersCount}");
throw new RegressionTestException($@"Expected {ExpectedOrdersCount} orders to have been submitted and filled, half for buying the strategy and the other half for the liquidation. Actual {ordersCount}");
}
}

View File

@@ -49,7 +49,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol);
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
public override void OnData(Slice slice)

View File

@@ -40,7 +40,7 @@ namespace QuantConnect.Algorithm.CSharp
// Subscribe to GOOG Options
var option = AddOption("GOOG");
option.SetFilter(x => x.CallsOnly().Strikes(0, 1).Expiration(0, 30));
option.SetFilter(x => x.StandardsOnly().CallsOnly().Strikes(0, 1).Expiration(0, 30));
}
public override void OnData(Slice slice)

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.CSharp</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.CSharp</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -32,7 +32,7 @@
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="Accord" Version="3.6.0" />
<PackageReference Include="Accord.Fuzzy" Version="3.6.0" />
<PackageReference Include="Accord.MachineLearning" Version="3.6.0" />

View File

@@ -49,6 +49,7 @@ namespace QuantConnect.Algorithm.CSharp
var equitySymbol = AddEquity("GOOG", leverage: 4, fillForward: true).Symbol;
_option = AddOption(equitySymbol, fillForward: true);
_option.SetFilter(optionFilterUniverse => optionFilterUniverse
.StandardsOnly()
.Strikes(-2, 2)
.Expiration(0, 180));
}
@@ -136,17 +137,13 @@ namespace QuantConnect.Algorithm.CSharp
var expectedEntryQuantity = leg.Quantity * _comboQuantity;
if (entryOrderTicket.Quantity != expectedEntryQuantity || entryOrderTicket.QuantityFilled != expectedEntryQuantity)
{
throw new RegressionTestException($@"Entry order ticket quantity and filled quantity do not match expected quantity for leg {i
}. Expected: {expectedEntryQuantity}. Actual quantity: {entryOrderTicket.Quantity}. Actual filled quantity: {
entryOrderTicket.QuantityFilled}");
throw new RegressionTestException($@"Entry order ticket quantity and filled quantity do not match expected quantity for leg {i}. Expected: {expectedEntryQuantity}. Actual quantity: {entryOrderTicket.Quantity}. Actual filled quantity: {entryOrderTicket.QuantityFilled}");
}
var expectedExitQuantity = -expectedEntryQuantity;
if (exitOrderTicket.Quantity != expectedExitQuantity || exitOrderTicket.QuantityFilled != expectedExitQuantity)
{
throw new RegressionTestException($@"Exit order ticket quantity and filled quantity do not match expected quantity for leg {i
}. Expected: {expectedExitQuantity}. Actual quantity: {exitOrderTicket.Quantity}. Actual filled quantity: {
exitOrderTicket.QuantityFilled}");
throw new RegressionTestException($@"Exit order ticket quantity and filled quantity do not match expected quantity for leg {i}. Expected: {expectedExitQuantity}. Actual quantity: {exitOrderTicket.Quantity}. Actual filled quantity: {exitOrderTicket.QuantityFilled}");
}
}
}

View File

@@ -47,7 +47,7 @@ namespace QuantConnect.Algorithm.CSharp
SetCash(500000);
var option = AddOption("GOOG", Resolution.Minute);
option.SetFilter(universe => universe.Strikes(-1, 1).Expiration(0, 62));
option.SetFilter(universe => universe.StandardsOnly().Strikes(-1, 1).Expiration(0, 62));
_symbol = option.Symbol;
}

View File

@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equitySymbol);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
public override void OnData(Slice slice)
@@ -124,8 +124,7 @@ namespace QuantConnect.Algorithm.CSharp
if (positionQuantityForDeltaWithPositionGroupBuyingPowerModel != expectedQuantity)
{
throw new RegressionTestException($@"Expected position quantity for delta buying power to be {expectedQuantity} but was {
positionQuantityForDeltaWithPositionGroupBuyingPowerModel}");
throw new RegressionTestException($@"Expected position quantity for delta buying power to be {expectedQuantity} but was {positionQuantityForDeltaWithPositionGroupBuyingPowerModel}");
}
var position = positionGroup.Positions.Single();
@@ -144,8 +143,7 @@ namespace QuantConnect.Algorithm.CSharp
if (positionQuantityForDeltaWithSecurityPositionGroupBuyingPowerModel != expectedSingleSecurityModelsQuantity ||
positionQuantityForDeltaWithSecurityBuyingPowerModel != expectedSingleSecurityModelsQuantity)
{
throw new RegressionTestException($@"Expected order quantity for delta buying power calls from default buying power models to return {
expectedSingleSecurityModelsQuantity}. Results were:" +
throw new RegressionTestException($@"Expected order quantity for delta buying power calls from default buying power models to return {expectedSingleSecurityModelsQuantity}. Results were:" +
$" \nSecurityPositionGroupBuyingPowerModel: {positionQuantityForDeltaWithSecurityPositionGroupBuyingPowerModel}" +
$" \nBuyingPowerModel: {positionQuantityForDeltaWithSecurityBuyingPowerModel}\n");
}

View File

@@ -54,7 +54,8 @@ namespace QuantConnect.Algorithm.CSharp
{
if (Time.Hour == 9 && Time.Minute == 58)
{
AddOption(UnderlyingTicker);
var option = AddOption(UnderlyingTicker);
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
}
AssertValue(slice);

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.Framework</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.Framework</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -29,7 +29,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="Accord" Version="3.6.0" />
<PackageReference Include="Accord.Math" Version="3.6.0" />
<PackageReference Include="Accord.Statistics" Version="3.6.0" />

View File

@@ -33,7 +33,7 @@ class BasicTemplateOptionEquityStrategyAlgorithm(QCAlgorithm):
self._option_symbol = option.symbol
# set our strike/expiry filter for this option chain
option.set_filter(lambda u: (u.strikes(-2, +2)
option.set_filter(lambda u: (u.standards_only().strikes(-2, +2)
# Expiration method accepts TimeSpan objects or integer for days.
# The following statements yield the same filtering criteria
.expiration(0, 180)))

View File

@@ -39,8 +39,7 @@ class BasicTemplateOptionStrategyAlgorithm(QCAlgorithm):
# set our strike/expiry filter for this option chain
# SetFilter method accepts timedelta objects or integer for days.
# The following statements yield the same filtering criteria
option.set_filter(-2, +2, 0, 180)
# option.set_filter(-2,2, timedelta(0), timedelta(180))
option.set_filter(lambda u: (u.standards_only().strikes(-2, +2).expiration(0, 180)))
# use the underlying equity as the benchmark
self.set_benchmark("GOOG")

View File

@@ -34,7 +34,7 @@ class BasicTemplateOptionsAlgorithm(QCAlgorithm):
self.option_symbol = option.symbol
# set our strike/expiry filter for this option chain
option.set_filter(lambda u: (u.strikes(-2, +2)
option.set_filter(lambda u: (u.standards_only().strikes(-2, +2)
# Expiration method accepts TimeSpan objects or integer for days.
# The following statements yield the same filtering criteria
.expiration(0, 180)))

View File

@@ -34,7 +34,7 @@ class BasicTemplateOptionsHourlyAlgorithm(QCAlgorithm):
self.option_symbol = option.symbol
# set our strike/expiry filter for this option chain
option.set_filter(lambda u: (u.strikes(-2, +2)
option.set_filter(lambda u: (u.standards_only().strikes(-2, +2)
# Expiration method accepts TimeSpan objects or integer for days.
# The following statements yield the same filtering criteria
.expiration(0, 180)))

View File

@@ -28,7 +28,7 @@ class ComboOrderTicketDemoAlgorithm(QCAlgorithm):
option = self.add_option(equity.symbol, fill_forward=True)
self._option_symbol = option.symbol
option.set_filter(lambda u: u.strikes(-2, +2).expiration(0, 180))
option.set_filter(lambda u: u.standards_only().strikes(-2, +2).expiration(0, 180))
self._open_market_orders = []
self._open_leg_limit_orders = []

View File

@@ -33,7 +33,7 @@ class NullBuyingPowerOptionBullCallSpreadAlgorithm(QCAlgorithm):
option = self.add_option(equity.symbol)
self.option_symbol = option.symbol
option.set_filter(-2, 2, 0, 180)
option.set_filter(lambda u: u.standards_only().strikes(-2, +2).expiration(0, 180))
def on_data(self, slice):
if self.portfolio.invested or not self.is_market_open(self.option_symbol):

View File

@@ -32,7 +32,7 @@ class NullMarginMultipleOrdersRegressionAlgorithm(QCAlgorithm):
option = self.add_option(equity.symbol, fill_forward=True)
self._option_symbol = option.symbol
option.set_filter(lambda u: u.strikes(-2, +2).expiration(0, 180))
option.set_filter(lambda u: u.standards_only().strikes(-2, +2).expiration(0, 180))
def on_data(self, data: Slice):
if not self.portfolio.invested:

View File

@@ -0,0 +1,46 @@
# 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.
from AlgorithmImports import *
### <summary>
### Verifies that weekly option contracts are included when no standard contracts are available.
### </summary>
class OptionChainIncludeWeeklysByDefaultRegressionAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2015, 12, 24)
self.set_end_date(2015, 12, 24)
self.option = self.add_option("GOOG")
self.option_symbol = self.option.Symbol
self.option.set_filter(lambda u: u.strikes(-8, 8).expiration(0, 0))
self.weekly_count = 0
self.total_count = 0
def on_data(self, data):
chain = data.option_chains.get(self.option_symbol)
if chain:
self.total_count += len(chain.contracts)
for contract in chain.contracts.values():
if not OptionSymbol.is_standard(contract.symbol):
self.weekly_count += 1
def on_end_of_algorithm(self):
if self.weekly_count == 0:
raise RegressionTestException("No weekly contracts found")
if self.total_count != self.weekly_count:
raise RegressionTestException("When no standard option expirations are available, the option chain must fall back to weekly contracts only")

View File

@@ -28,7 +28,7 @@ class OptionChainedUniverseSelectionModelRegressionAlgorithm(QCAlgorithm):
self.add_universe_selection(
OptionChainedUniverseSelectionModel(
universe,
lambda u: (u.strikes(-2, +2)
lambda u: (u.standards_only().strikes(-2, +2)
# Expiration method accepts TimeSpan objects or integer for days.
# The following statements yield the same filtering criteria
.expiration(0, 180))

View File

@@ -24,6 +24,8 @@ class OptionPriceModelForSupportedAmericanOptionRegressionAlgorithm(OptionPriceM
self.set_end_date(2014, 6, 9)
option = self.add_option("AAPL", Resolution.MINUTE)
option.set_filter(lambda u: u.standards_only().strikes(-1, 1).expiration(0, 35))
# BaroneAdesiWhaley model supports American style options
option.price_model = OptionPriceModels.barone_adesi_whaley()

View File

@@ -24,6 +24,8 @@ class OptionPriceModelForUnsupportedAmericanOptionRegressionAlgorithm(OptionPric
self.set_end_date(2014, 6, 9)
option = self.add_option("AAPL", Resolution.MINUTE)
option.set_filter(lambda u: u.standards_only().strikes(-1, 1).expiration(0, 35))
# BlackSholes model does not support American style options
option.price_model = OptionPriceModels.black_scholes()

View File

@@ -27,7 +27,7 @@ class OptionStrategyFactoryMethodsBaseAlgorithm(QCAlgorithm):
option = self.add_option("GOOG")
self._option_symbol = option.symbol
option.set_filter(-2, +2, 0, 180)
option.set_filter(lambda u: u.standards_only().strikes(-2, +2).expiration(0, 180))
self.set_benchmark("GOOG")

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.Python</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.Python</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<OutputPath>bin\$(Configuration)\</OutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -37,7 +37,7 @@
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
</ItemGroup>
<ItemGroup>
<Content Include="OptionUniverseFilterGreeksShortcutsRegressionAlgorithm.py" />

View File

@@ -53,7 +53,8 @@ namespace QuantConnect.Algorithm
"IsReady",
"Window",
"Item",
"WarmUpPeriod"
"WarmUpPeriod",
"Period"
};
/// <summary>
@@ -489,6 +490,26 @@ namespace QuantConnect.Algorithm
return correlation;
}
/// <summary>
/// Creates a Covariance indicator for the given target symbol in relation with the reference used.
/// The indicator will be automatically updated on the given resolution.
/// </summary>
/// <param name="target">The target symbol whose Covariance value we want</param>
/// <param name="reference">The reference symbol to compare with the target symbol</param>
/// <param name="period">The period of the Covariance indicator</param>
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The Covariance indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public Covariance COV(Symbol target, Symbol reference, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(QuantConnect.Symbol.None, $"COV({period})", resolution);
var covariance = new Covariance(name, target, reference, period);
InitializeIndicator(covariance, resolution, selector, target, reference);
return covariance;
}
/// <summary>
/// Creates a new CommodityChannelIndex indicator. The indicator will be automatically
/// updated on the given resolution.

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm</RootNamespace>
<AssemblyName>QuantConnect.Algorithm</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -29,7 +29,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="NodaTime" Version="3.0.5" />

View File

@@ -19,6 +19,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Security.Policy;
using Python.Runtime;
using QuantConnect.Interfaces;
@@ -179,9 +180,11 @@ namespace QuantConnect.AlgorithmFactory
{
PythonEngine.Exec(
@"
import logging, os, sys
sys.stdout = open(os.devnull, 'w')
logging.captureWarnings(True)"
from logging import captureWarnings
from os import devnull
from sys import stdout
stdout = open(devnull, 'w')
captureWarnings(True)"
);
}
}
@@ -211,40 +214,14 @@ logging.captureWarnings(True)"
try
{
byte[] debugInformationBytes = null;
// if the assembly is located in the base directory then don't bother loading the pdbs
// manually, they'll be loaded automatically by the .NET runtime.
var directoryName = new FileInfo(assemblyPath).DirectoryName;
if (directoryName != null && directoryName.TrimEnd(Path.DirectorySeparatorChar) != AppDomain.CurrentDomain.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar))
{
// see if the pdb exists
var mdbFilename = assemblyPath + ".mdb";
var pdbFilename = assemblyPath.Substring(0, assemblyPath.Length - 4) + ".pdb";
if (File.Exists(pdbFilename))
{
debugInformationBytes = File.ReadAllBytes(pdbFilename);
}
// see if the mdb exists
if (File.Exists(mdbFilename))
{
debugInformationBytes = File.ReadAllBytes(mdbFilename);
}
}
var assemblyFile = new FileInfo(assemblyPath);
var directoryName = assemblyFile.DirectoryName;
//Load the assembly:
Assembly assembly;
if (debugInformationBytes == null)
{
Log.Trace("Loader.TryCreateILAlgorithm(): Loading only the algorithm assembly");
assembly = Assembly.LoadFrom(assemblyPath);
}
else
{
Log.Trace("Loader.TryCreateILAlgorithm(): Loading debug information with algorithm");
var assemblyBytes = File.ReadAllBytes(assemblyPath);
assembly = Assembly.Load(assemblyBytes, debugInformationBytes);
}
var loader = new PluginLoadContext(directoryName);
var assembly = loader.LoadFromAssemblyPath(assemblyFile.FullName);
//Get the list of extention classes in the library:
var types = GetExtendedTypeNames(assembly);
@@ -277,7 +254,6 @@ logging.captureWarnings(True)"
{
Log.Trace("Loader.TryCreateILAlgorithm(): Loaded " + algorithmInstance.GetType().Name);
}
}
catch (ReflectionTypeLoadException err)
{
@@ -302,7 +278,7 @@ logging.captureWarnings(True)"
/// <returns>String list of types available.</returns>
public static List<string> GetExtendedTypeNames(Assembly assembly)
{
var types = new List<string>();
List<string> types;
try
{
Type[] assemblyTypes;
@@ -330,20 +306,22 @@ logging.captureWarnings(True)"
{
types = (from t in assemblyTypes
where t.IsClass // require class
where !t.IsAbstract // require concrete impl
where AlgorithmInterfaceType.IsAssignableFrom(t) // require derived from IAlgorithm
where t.FullName != AlgorithmBaseTypeFullName // require not equal to QuantConnect.QCAlgorithm
where t.FullName != FrameworkBaseTypeFullName // require not equal to QuantConnect.QCAlgorithmFramework
where t.GetConstructor(Type.EmptyTypes) != null // require default ctor
&& !t.IsAbstract // require concrete impl
&& AlgorithmInterfaceType.IsAssignableFrom(t) // require derived from IAlgorithm
&& t.FullName != AlgorithmBaseTypeFullName // require not equal to QuantConnect.QCAlgorithm
&& t.FullName != FrameworkBaseTypeFullName // require not equal to QuantConnect.QCAlgorithmFramework
&& t.GetConstructor(Type.EmptyTypes) != null // require default ctor
select t.FullName).ToList();
}
else
{
types = [];
Log.Error("API.GetExtendedTypeNames(): No types found in assembly.");
}
}
catch (Exception err)
{
types = [];
Log.Error(err);
}
@@ -397,6 +375,37 @@ logging.captureWarnings(True)"
}
}
} // End Algorithm Factory Class
class PluginLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
Resolving += (context, assemblyName) =>
{
var path = Path.Combine(Composer.PluginDirectory, $"{assemblyName.Name}.dll");
try
{
return context.LoadFromAssemblyPath(path);
}
catch
{
return null;
}
};
}
protected override Assembly Load(AssemblyName assemblyName)
{
var path = _resolver.ResolveAssemblyToPath(assemblyName);
if (path != null)
{
return LoadFromAssemblyPath(path);
}
return null;
}
}
} // End Algorithm Factory Class
} // End QC Namespace.

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.AlgorithmFactory</RootNamespace>
<AssemblyName>QuantConnect.AlgorithmFactory</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -28,7 +28,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="NodaTime" Version="3.0.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -82,7 +82,7 @@ namespace QuantConnect.Api
/// </summary>
public virtual void Initialize(int userId, string token, string dataFolder)
{
ApiConnection = new ApiConnection(userId, token);
ApiConnection = CreateApiConnection(userId, token);
_dataFolder = dataFolder?.Replace("\\", "/", StringComparison.InvariantCulture);
//Allow proper decoding of orders from the API.
@@ -1472,6 +1472,14 @@ namespace QuantConnect.Api
return (apiConnection ?? ApiConnection).TryRequest(request, out result, timeout);
}
/// <summary>
/// Create the api connection instance to use
/// </summary>
protected virtual ApiConnection CreateApiConnection(int userId, string token)
{
return new ApiConnection(userId, token);
}
/// <summary>
/// Helper method that will execute the given api request and throw an exception if it fails
/// </summary>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Api</RootNamespace>
<AssemblyName>QuantConnect.Api</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Brokerages</RootNamespace>
<AssemblyName>QuantConnect.Brokerages</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>

View File

@@ -27,7 +27,7 @@ namespace QuantConnect.Api
/// User ID
/// </summary>
[JsonProperty(PropertyName = "uid")]
public int Uid { get; set; }
public int? Uid { get; set; }
/// <summary>
/// Indicate if the user have live control
@@ -46,7 +46,7 @@ namespace QuantConnect.Api
/// The user public ID
/// </summary>
[JsonProperty(PropertyName = "publicId")]
public string PublicId { get; set; }
public string PublicId { get; set; }
/// <summary>
/// The url of the user profile image
@@ -119,7 +119,7 @@ namespace QuantConnect.Api
/// The chart name
/// </summary>
[JsonProperty(PropertyName = "chartName")]
public string ChartName { get; set;}
public string ChartName { get; set; }
/// <summary>
/// Width of the chart
@@ -328,7 +328,7 @@ namespace QuantConnect.Api
/// <summary>
/// Configuration of the backtest view grid
/// </summary>
[JsonProperty(PropertyName = "grid" )]
[JsonProperty(PropertyName = "grid")]
public Grid Grid { get; set; }
/// <summary>
@@ -365,7 +365,7 @@ namespace QuantConnect.Api
/// Indicates if the project is running or not
/// </summary>
[JsonProperty(PropertyName = "codeRunning")]
public bool CodeRunning { get; set; }
public bool CodeRunning { get; set; }
/// <summary>
/// LEAN environment of the project running on

View File

@@ -228,7 +228,7 @@ namespace QuantConnect
};
/// <summary>
/// Define some StableCoins that don't have direct pairs for base currencies in our SPDB in Binance market
/// Define some StableCoins that don't have direct pairs for base currencies in our SPDB in Bybit market
/// This is because some CryptoExchanges do not define direct pairs with the stablecoins they offer.
///
/// We use this to allow setting cash amounts for these stablecoins without needing a conversion
@@ -246,6 +246,18 @@ namespace QuantConnect
"DAIUSD"
};
/// <summary>
/// Define some StableCoins that don't have direct pairs for base currencies in our SPDB in dYdX market
/// This is because some CryptoExchanges do not define direct pairs with the stablecoins they offer.
///
/// We use this to allow setting cash amounts for these stablecoins without needing a conversion
/// security.
/// </summary>
private static readonly HashSet<string> _stableCoinsWithoutPairsdYdX = new HashSet<string>
{
"USDCUSD"
};
/// <summary>
/// Dictionary to save StableCoins in different Markets
/// </summary>
@@ -255,6 +267,7 @@ namespace QuantConnect
{ Market.Bitfinex , _stableCoinsWithoutPairsBitfinex},
{ Market.Coinbase, _stableCoinsWithoutPairsCoinbase},
{ Market.Bybit , _stableCoinsWithoutPairsBybit},
{ Market.dYdX , _stableCoinsWithoutPairsdYdX}
};
/// <summary>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>QuantConnect.Common</AssemblyName>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
@@ -35,7 +35,7 @@
<Message Text="SelectedOptimization $(SelectedOptimization)" Importance="high" />
</Target>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="CloneExtensions" Version="1.3.0" />
<PackageReference Include="fasterflect" Version="3.0.0" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />

View File

@@ -262,6 +262,14 @@ namespace QuantConnect.Securities
var cfdEntries = GetAvailableSymbolPropertiesDatabaseEntries(SecurityType.Cfd, marketMap, markets);
var cryptoEntries = GetAvailableSymbolPropertiesDatabaseEntries(SecurityType.Crypto, marketMap, markets);
if (marketMap.TryGetValue(SecurityType.CryptoFuture, out var cryptoFutureMarket) && cryptoFutureMarket == Market.dYdX)
{
// Put additional logic for dYdX crypto futures as they don't have Crypto (Spot) market
// Also need to add them first to give the priority
// TODO: remove once dydx SPOT market will be imlemented
cryptoEntries = GetAvailableSymbolPropertiesDatabaseEntries(SecurityType.CryptoFuture, marketMap, markets).Concat(cryptoEntries);
}
var potentialEntries = forexEntries
.Concat(cfdEntries)
.Concat(cryptoEntries)

View File

@@ -27,8 +27,8 @@ namespace QuantConnect.Securities
/// Used by OptionFilterUniverse and FutureFilterUniverse
/// </summary>
public abstract class ContractSecurityFilterUniverse<T, TData> : IDerivativeSecurityFilterUniverse<TData>
where T: ContractSecurityFilterUniverse<T, TData>
where TData: IChainUniverseData
where T : ContractSecurityFilterUniverse<T, TData>
where TData : IChainUniverseData
{
private bool _alreadyAppliedTypeFilters;
@@ -51,11 +51,16 @@ namespace QuantConnect.Securities
Weekly = 2
}
/// <summary>
/// The default expiration type filter value
/// </summary>
protected static readonly ContractExpirationType DefaultExpirationType = ContractExpirationType.Standard | ContractExpirationType.Weekly;
/// <summary>
/// Expiration Types allowed through the filter
/// Standards only by default
/// </summary>
protected ContractExpirationType Type { get; set; } = ContractExpirationType.Standard;
protected ContractExpirationType Type { get; set; } = DefaultExpirationType;
/// <summary>
/// The local exchange current time
@@ -107,6 +112,7 @@ namespace QuantConnect.Securities
/// </summary>
protected ContractSecurityFilterUniverse()
{
Type = DefaultExpirationType;
}
/// <summary>
@@ -116,7 +122,7 @@ namespace QuantConnect.Securities
{
Data = allData;
LocalTime = localTime;
Type = ContractExpirationType.Standard;
Type = DefaultExpirationType;
}
/// <summary>
@@ -139,7 +145,7 @@ namespace QuantConnect.Securities
{
if (_alreadyAppliedTypeFilters)
{
return (T) this;
return (T)this;
}
// memoization map for ApplyTypesFilter()
@@ -174,7 +180,7 @@ namespace QuantConnect.Securities
}).ToList();
_alreadyAppliedTypeFilters = true;
return (T) this;
return (T)this;
}
/// <summary>
@@ -186,7 +192,7 @@ namespace QuantConnect.Securities
{
Data = allData;
LocalTime = localTime;
Type = ContractExpirationType.Standard;
Type = DefaultExpirationType;
_alreadyAppliedTypeFilters = false;
}
@@ -211,6 +217,7 @@ namespace QuantConnect.Securities
/// Includes universe of non-standard weeklys contracts (if any) into selection
/// </summary>
/// <returns>Universe with filter applied</returns>
[Obsolete("IncludeWeeklys is obsolete because weekly contracts are now included by default.")]
public T IncludeWeeklys()
{
if (_alreadyAppliedTypeFilters)
@@ -241,11 +248,11 @@ namespace QuantConnect.Securities
{
ApplyTypesFilter();
var ordered = Data.OrderBy(x => x.ID.Date).ToList();
if (ordered.Count == 0) return (T) this;
if (ordered.Count == 0) return (T)this;
var frontMonth = ordered.TakeWhile(x => ordered[0].ID.Date == x.ID.Date);
Data = frontMonth.ToList();
return (T) this;
return (T)this;
}
/// <summary>
@@ -256,11 +263,11 @@ namespace QuantConnect.Securities
{
ApplyTypesFilter();
var ordered = Data.OrderBy(x => x.ID.Date).ToList();
if (ordered.Count == 0) return (T) this;
if (ordered.Count == 0) return (T)this;
var backMonths = ordered.SkipWhile(x => ordered[0].ID.Date == x.ID.Date);
Data = backMonths.ToList();
return (T) this;
return (T)this;
}
/// <summary>
@@ -351,7 +358,7 @@ namespace QuantConnect.Securities
public T Contracts(IEnumerable<Symbol> contracts)
{
AllSymbols = contracts.ToList();
return (T) this;
return (T)this;
}
/// <summary>
@@ -376,7 +383,7 @@ namespace QuantConnect.Securities
{
// force materialization using ToList
AllSymbols = contractSelector(Data).ToList();
return (T) this;
return (T)this;
}
/// <summary>
@@ -400,7 +407,7 @@ namespace QuantConnect.Securities
[Obsolete("Deprecated as of 2023-12-13. Filters are always non-dynamic as of now, which means they will only bee applied daily.")]
public T OnlyApplyFilterAtMarketOpen()
{
return (T) this;
return (T)this;
}
/// <summary>

View File

@@ -158,7 +158,7 @@ namespace QuantConnect.Securities.Future
}
// Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time, Symbol.Create(Futures.Indices.SP500EMini, SecurityType.Future, Market.CME));
return thirdFriday.Add(new TimeSpan(13,30,0));
})
},
@@ -217,7 +217,7 @@ namespace QuantConnect.Securities.Future
}
// Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time, Symbol.Create(Futures.Indices.NASDAQ100EMini, SecurityType.Future, Market.CME));
return thirdFriday.Add(new TimeSpan(13,30,0));
})
},
@@ -231,7 +231,7 @@ namespace QuantConnect.Securities.Future
}
// Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time, Symbol.Create(Futures.Indices.Dow30EMini, SecurityType.Future, Market.CBOT));
return thirdFriday.Add(new TimeSpan(13,30,0));
})
},
@@ -245,7 +245,7 @@ namespace QuantConnect.Securities.Future
}
// Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time, Symbol.Create(Futures.Indices.Russell2000EMini, SecurityType.Future, Market.CME));
return thirdFriday.Add(new TimeSpan (13,30,0));
})
},
@@ -3208,7 +3208,7 @@ namespace QuantConnect.Securities.Future
}
// Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time, Symbol.Create(Futures.Indices.MicroSP500EMini, SecurityType.Future, Market.CME));
return thirdFriday.Add(new TimeSpan(13,30,0));
})
},
@@ -3222,7 +3222,7 @@ namespace QuantConnect.Securities.Future
}
// Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time, Symbol.Create(Futures.Indices.MicroNASDAQ100EMini, SecurityType.Future, Market.CME));
return thirdFriday.Add(new TimeSpan(13,30,0));
})
},
@@ -3236,7 +3236,7 @@ namespace QuantConnect.Securities.Future
}
// Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time, Symbol.Create(Futures.Indices.MicroRussell2000EMini, SecurityType.Future, Market.CME));
return thirdFriday.Add(new TimeSpan(13,30,0));
})
},
@@ -3250,7 +3250,7 @@ namespace QuantConnect.Securities.Future
}
// Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time, Symbol.Create(Futures.Indices.MicroDow30EMini, SecurityType.Future, Market.CBOT));
return thirdFriday.Add(new TimeSpan(13,30,0));
})
},

View File

@@ -37,6 +37,11 @@ namespace QuantConnect.Securities.Future
private static readonly Symbol _zw = Symbol.Create("ZW", SecurityType.Future, Market.CBOT);
private static readonly Symbol _tn = Symbol.Create("TN", SecurityType.Future, Market.CBOT);
private static readonly Symbol _aud = Symbol.Create("6A", SecurityType.Future, Market.CME);
private static readonly Symbol _gbp = Symbol.Create("6B", SecurityType.Future, Market.CME);
private static readonly Symbol _mxn = Symbol.Create("6M", SecurityType.Future, Market.CME);
private static readonly Symbol _jpy = Symbol.Create("6J", SecurityType.Future, Market.CME);
private static readonly Symbol _eur = Symbol.Create("6E", SecurityType.Future, Market.CME);
private static readonly Symbol _cad = Symbol.Create("6C", SecurityType.Future, Market.CME);
private static Dictionary<string, Func<DateTime, List<Symbol>>> _futuresListingRules = new Dictionary<string, Func<DateTime, List<Symbol>>>
{
@@ -73,7 +78,12 @@ namespace QuantConnect.Securities.Future
t,
7,
new FuturesListingCycles(new[] { 3, 5, 7, 9, 12 }, 15)) },
{ "6A", t => QuarterlyContracts(_aud, t, 8) }
{ "6A", t => QuarterlyContracts(_aud, t, 8) },
{ "6B", t => QuarterlyContracts(_gbp, t, 8) },
{ "6M", t => QuarterlyContracts(_mxn, t, 8) },
{ "6J", t => QuarterlyContracts(_jpy, t, 8) },
{ "6E", t => QuarterlyContracts(_eur, t, 8) },
{ "6C", t => QuarterlyContracts(_cad, t, 8) },
};
/// <summary>

View File

@@ -50,6 +50,7 @@ namespace QuantConnect.Securities.FutureOption
private static readonly Symbol _jpu = Symbol.CreateCanonicalOption(Symbol.Create("6J", SecurityType.Future, Market.CME));
private static readonly Symbol _chu = Symbol.CreateCanonicalOption(Symbol.Create("6S", SecurityType.Future, Market.CME));
private static readonly Symbol _nzd = Symbol.CreateCanonicalOption(Symbol.Create("6N", SecurityType.Future, Market.CME));
private static readonly Symbol _mxn = Symbol.CreateCanonicalOption(Symbol.Create("6M", SecurityType.Future, Market.CME));
private static readonly Symbol _le = Symbol.CreateCanonicalOption(Symbol.Create("LE", SecurityType.Future, Market.CME));
private static readonly Symbol _he = Symbol.CreateCanonicalOption(Symbol.Create("HE", SecurityType.Future, Market.CME));
private static readonly Symbol _lbr = Symbol.CreateCanonicalOption(Symbol.Create("LBR", SecurityType.Future, Market.CME));
@@ -97,6 +98,7 @@ namespace QuantConnect.Securities.FutureOption
{ _jpu, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_jpu.Underlying, expiryMonth) },
{ _chu, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_chu.Underlying, expiryMonth) },
{ _nzd, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_nzd.Underlying, expiryMonth) },
{ _mxn, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_mxn.Underlying, expiryMonth) },
{ _le, expiryMonth => FirstFridayOfContractMonth(_le.Underlying, expiryMonth) },
{ _he, expiryMonth => TenthBusinessDayOfContractMonth(_he.Underlying, expiryMonth) },
{ _lbr, expiryMonth => LastBusinessDayInPrecedingMonthFromContractMonth(_lbr.Underlying, expiryMonth) },

View File

@@ -63,7 +63,12 @@ namespace QuantConnect.Securities.FutureOption
{ "GC", (d, _) => ContractMonthEvenOddMonth(d, false) },
// CME
{ "6A", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6A", SecurityType.Future, Market.CME), d, ld.Value) }
{ "6A", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6A", SecurityType.Future, Market.CME), d, ld.Value) },
{ "6B", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6B", SecurityType.Future, Market.CME), d, ld.Value) },
{ "6M", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6M", SecurityType.Future, Market.CME), d, ld.Value) },
{ "6J", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6J", SecurityType.Future, Market.CME), d, ld.Value) },
{ "6E", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6E", SecurityType.Future, Market.CME), d, ld.Value) },
{ "6C", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6C", SecurityType.Future, Market.CME), d, ld.Value) },
};
/// <summary>

View File

@@ -31,7 +31,7 @@ namespace QuantConnect.Securities
/// Provides access to exchange hours and raw data times zones in various markets
/// </summary>
[JsonConverter(typeof(MarketHoursDatabaseJsonConverter))]
public class MarketHoursDatabase : BaseSecurityDatabase<MarketHoursDatabase, MarketHoursDatabase.Entry>
public class MarketHoursDatabase : BaseSecurityDatabase<MarketHoursDatabase, Lazy<MarketHoursDatabase.Entry>>
{
private readonly bool _forceExchangeAlwaysOpen = Config.GetBool("force-exchange-always-open");
@@ -40,7 +40,7 @@ namespace QuantConnect.Securities
/// <summary>
/// Gets all the exchange hours held by this provider
/// </summary>
public List<KeyValuePair<SecurityDatabaseKey, Entry>> ExchangeHoursListing => Entries.ToList();
public List<KeyValuePair<SecurityDatabaseKey, Entry>> ExchangeHoursListing => Entries.ToList(x => new KeyValuePair<SecurityDatabaseKey, Entry>(x.Key, x.Value.Value));
/// <summary>
/// Gets a <see cref="MarketHoursDatabase"/> that always returns <see cref="SecurityExchangeHours.AlwaysOpen"/>
@@ -62,7 +62,7 @@ namespace QuantConnect.Securities
/// Initializes a new instance of the <see cref="MarketHoursDatabase"/> class
/// </summary>
private MarketHoursDatabase()
: this(new())
: this(new Dictionary<SecurityDatabaseKey, Entry>())
{
}
@@ -71,7 +71,16 @@ namespace QuantConnect.Securities
/// </summary>
/// <param name="exchangeHours">The full listing of exchange hours by key</param>
public MarketHoursDatabase(Dictionary<SecurityDatabaseKey, Entry> exchangeHours)
: base(exchangeHours, FromDataFolder, (entry, other) => entry.Update(other))
: this(exchangeHours.ToDictionary(kvp => kvp.Key, kvp => new Lazy<Entry>(kvp.Value)))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MarketHoursDatabase"/> class
/// </summary>
/// <param name="exchangeHours">The full listing of exchange hours by key</param>
public MarketHoursDatabase(Dictionary<SecurityDatabaseKey, Lazy<Entry>> exchangeHours)
: base(exchangeHours, FromDataFolder, (entry, other) => entry.Value.Update(other.Value))
{
}
@@ -139,7 +148,9 @@ namespace QuantConnect.Securities
/// <returns>A new instance of the <see cref="MarketHoursDatabase"/> class</returns>
public static MarketHoursDatabase FromFile(string path)
{
return JsonConvert.DeserializeObject<MarketHoursDatabase>(File.ReadAllText(path));
using var stream = File.OpenRead(path);
var result = Extensions.DeserializeJson<MarketHoursDatabaseJsonConverter.MarketHoursDatabaseJson>(stream);
return result.Convert();
}
/// <summary>
@@ -161,7 +172,7 @@ namespace QuantConnect.Securities
var entry = new Entry(dataTimeZone, exchangeHours);
lock (DataFolderDatabaseLock)
{
Entries[key] = entry;
Entries[key] = new Lazy<Entry>(entry);
CustomEntries.Add(key);
}
return entry;
@@ -252,16 +263,22 @@ namespace QuantConnect.Securities
private bool TryGetEntryImpl(string market, string symbol, SecurityType securityType, out Entry entry)
{
entry = null;
var symbolKey = new SecurityDatabaseKey(market, symbol, securityType);
return Entries.TryGetValue(symbolKey, out entry)
if (Entries.TryGetValue(symbolKey, out var lazyEntry)
// now check with null symbol key
|| Entries.TryGetValue(symbolKey.CreateCommonKey(), out entry)
|| Entries.TryGetValue(symbolKey.CreateCommonKey(), out lazyEntry)
// if FOP check for future
|| securityType == SecurityType.FutureOption && TryGetEntry(market,
FuturesOptionsSymbolMappings.MapFromOption(symbol), SecurityType.Future, out entry)
// if custom data type check for type specific entry
|| (securityType == SecurityType.Base && SecurityIdentifier.TryGetCustomDataType(symbol, out var customType)
&& Entries.TryGetValue(new SecurityDatabaseKey(market, $"TYPE.{customType}", securityType), out entry));
&& Entries.TryGetValue(new SecurityDatabaseKey(market, $"TYPE.{customType}", securityType), out lazyEntry)))
{
entry ??= lazyEntry.Value;
return true;
}
return false;
}
/// <summary>

View File

@@ -58,6 +58,7 @@ namespace QuantConnect.Securities
/// <summary>
/// Constructs OptionFilterUniverse
/// By default, the filter includes both standard and weekly contracts.
/// </summary>
/// <param name="option">The canonical option chain security</param>
public OptionFilterUniverse(Option.Option option)

View File

@@ -622,7 +622,7 @@ namespace QuantConnect
return 2000 + parsed.ExpirationYearShort;
}
var baseYear = ((int)Math.Round(currentYear / 10.0)) * 10 + parsed.ExpirationYearShort;
var baseYear = ((int)Math.Floor(currentYear / 10.0)) * 10 + parsed.ExpirationYearShort;
while (baseYear < currentYear)
{
baseYear += 10;

View File

@@ -37,11 +37,19 @@ namespace QuantConnect.Util
/// </summary>
public class Composer
{
private static string PluginDirectory;
/// <summary>
/// The plugin directory source if any
/// </summary>
public static string PluginDirectory { get; private set; }
private static readonly Lazy<Composer> LazyComposer = new Lazy<Composer>(
() =>
{
PluginDirectory = Config.Get("plugin-directory");
var pluginDirectory = Config.Get("plugin-directory");
if (!string.IsNullOrEmpty(pluginDirectory))
{
PluginDirectory = new DirectoryInfo(pluginDirectory).FullName;
}
return new Composer();
});
@@ -87,7 +95,7 @@ namespace QuantConnect.Util
var loadFromPluginDir = !string.IsNullOrWhiteSpace(PluginDirectory)
&& Directory.Exists(PluginDirectory) &&
new DirectoryInfo(PluginDirectory).FullName != primaryDllLookupDirectory;
PluginDirectory != primaryDllLookupDirectory;
var fileNames = Directory.EnumerateFiles(primaryDllLookupDirectory, "*.dll");
if (loadFromPluginDir)
{
@@ -354,6 +362,11 @@ namespace QuantConnect.Util
var catalogs = new ConcurrentBag<ComposablePartCatalog>();
Parallel.ForEach(files, file =>
{
if (!Path.GetFileName(file).StartsWith($"{nameof(QuantConnect)}.", StringComparison.InvariantCulture))
{
return;
}
try
{
// we need to load assemblies so that C# algorithm dependencies are resolved correctly
@@ -370,12 +383,9 @@ namespace QuantConnect.Util
assembly = Assembly.LoadFrom(file);
}
if (Path.GetFileName(file).StartsWith($"{nameof(QuantConnect)}.", StringComparison.InvariantCulture))
foreach (var type in assembly.ExportedTypes.Where(type => !type.IsAbstract && !type.IsInterface && !type.IsEnum))
{
foreach (var type in assembly.ExportedTypes.Where(type => !type.IsAbstract && !type.IsInterface && !type.IsEnum))
{
exportedTypes.Add(type);
}
exportedTypes.Add(type);
}
var asmCatalog = new AssemblyCatalog(assembly);
var parts = asmCatalog.Parts.ToArray();
@@ -386,7 +396,10 @@ namespace QuantConnect.Util
}
catch (Exception ex)
{
Log.Trace($"Composer.LoadPartsSafely({file}): Skipping {ex.GetType().Name}: {ex.Message}");
if (!file.Contains("quickfix.fix", StringComparison.InvariantCultureIgnoreCase))
{
Log.Trace($"Composer.LoadPartsSafely({file}): Skipping {ex.GetType().Name}: {ex.Message}");
}
}
});

View File

@@ -98,33 +98,23 @@ namespace QuantConnect.Util
/// <returns>A new instance of the <see cref="MarketHoursDatabase"/> class</returns>
public MarketHoursDatabase Convert()
{
// first we parse the entries keys so that later we can sort by security type
var entries = new Dictionary<SecurityDatabaseKey, MarketHoursDatabaseEntryJson>(Entries.Count);
foreach (var entry in Entries)
var result = new Dictionary<SecurityDatabaseKey, Lazy<MarketHoursDatabase.Entry>>(Entries.Count);
foreach (var kvp in Entries)
{
try
{
var key = SecurityDatabaseKey.Parse(entry.Key);
if (key != null)
var key = SecurityDatabaseKey.Parse(kvp.Key);
result[key] = new Lazy<MarketHoursDatabase.Entry>(() =>
{
entries[key] = entry.Value;
}
}
catch (Exception err)
{
Log.Error(err);
}
}
var result = new Dictionary<SecurityDatabaseKey, MarketHoursDatabase.Entry>(Entries.Count);
// we sort so we process generic entries and non options first
foreach (var entry in entries.OrderBy(kvp => kvp.Key.Symbol != null ? 1 : 0).ThenBy(kvp => kvp.Key.SecurityType.IsOption() ? 1 : 0))
{
try
{
result.TryGetValue(entry.Key.CreateCommonKey(), out var marketEntry);
var underlyingEntry = GetUnderlyingEntry(entry.Key, result);
result[entry.Key] = entry.Value.Convert(underlyingEntry, marketEntry);
MarketHoursDatabase.Entry marketEntry = null;
if (key.Symbol != SecurityDatabaseKey.Wildcard)
{
result.TryGetValue(key.CreateCommonKey(), out var marketEntryLazy);
marketEntry = marketEntryLazy?.Value;
}
var underlyingEntry = GetUnderlyingEntry(key, result);
return kvp.Value.Convert(underlyingEntry, marketEntry);
});
}
catch (Exception err)
{
@@ -137,9 +127,9 @@ namespace QuantConnect.Util
/// <summary>
/// Helper method to get the already processed underlying entry for options
/// </summary>
private static MarketHoursDatabase.Entry GetUnderlyingEntry(SecurityDatabaseKey key, Dictionary<SecurityDatabaseKey, MarketHoursDatabase.Entry> result)
private static MarketHoursDatabase.Entry GetUnderlyingEntry(SecurityDatabaseKey key, Dictionary<SecurityDatabaseKey, Lazy<MarketHoursDatabase.Entry>> result)
{
MarketHoursDatabase.Entry underlyingEntry = null;
Lazy<MarketHoursDatabase.Entry> underlyingEntryLazy = null;
if (key.SecurityType.IsOption())
{
// if option, let's get the underlyings entry
@@ -147,15 +137,15 @@ namespace QuantConnect.Util
var underlying = OptionSymbol.MapToUnderlying(key.Symbol, key.SecurityType);
var underlyingKey = new SecurityDatabaseKey(key.Market, underlying, underlyingSecurityType);
if (!result.TryGetValue(underlyingKey, out underlyingEntry)
if (!result.TryGetValue(underlyingKey, out underlyingEntryLazy)
// let's retry with the wildcard
&& underlying != SecurityDatabaseKey.Wildcard)
{
var underlyingKeyWildCard = new SecurityDatabaseKey(key.Market, SecurityDatabaseKey.Wildcard, underlyingSecurityType);
result.TryGetValue(underlyingKeyWildCard, out underlyingEntry);
result.TryGetValue(underlyingKeyWildCard, out underlyingEntryLazy);
}
}
return underlyingEntry;
return underlyingEntryLazy?.Value;
}
}

View File

@@ -156,6 +156,37 @@ namespace QuantConnect.Util
return isNegative ? result * -1 : result;
}
/// <summary>
/// Gets an integer from a stream reader
/// </summary>
/// <param name="stream">The data stream</param>
/// <param name="delimiter">The data delimiter character to use, default is ','</param>
/// <returns>The integer instance read</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long GetInt64(this StreamReader stream, char delimiter = DefaultDelimiter)
{
var result = 0L;
var current = (char)stream.Read();
while (current == ' ')
{
current = (char)stream.Read();
}
var isNegative = current == '-';
if (isNegative)
{
current = (char)stream.Read();
}
while (!(current == delimiter || current == '\n' || current == '\r' && (stream.Peek() != '\n' || stream.Read() == '\n') || current == NoMoreData || current == ' '))
{
result = (current - '0') + result * 10L;
current = (char)stream.Read();
}
return isNegative ? result * -1L : result;
}
private readonly static ConcurrentBag<StringBuilder> StringBuilders = new();
/// <summary>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Compression</RootNamespace>
<AssemblyName>QuantConnect.Compression</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>

View File

@@ -146,7 +146,10 @@ namespace QuantConnect.Configuration
var token = GetToken(Settings.Value, key);
if (token == null)
{
Log.Trace(Invariant($"Config.Get(): Configuration key not found. Key: {key} - Using default value: {defaultValue}"));
if (Log.DebuggingEnabled)
{
Log.Debug(Invariant($"Config.Get(): Configuration key not found. Key: {key} - Using default value: {defaultValue}"));
}
return defaultValue;
}
return token.ToString();
@@ -227,18 +230,21 @@ namespace QuantConnect.Configuration
public static T GetValue<T>(string key, T defaultValue = default(T))
{
// special case environment requests
if (key == "environment" && typeof (T) == typeof (string)) return (T) (object) GetEnvironment();
if (key == "environment" && typeof(T) == typeof(string)) return (T)(object)GetEnvironment();
var token = GetToken(Settings.Value, key);
if (token == null)
{
var defaultValueString = defaultValue is IConvertible
? ((IConvertible) defaultValue).ToString(CultureInfo.InvariantCulture)
? ((IConvertible)defaultValue).ToString(CultureInfo.InvariantCulture)
: defaultValue is IFormattable
? ((IFormattable) defaultValue).ToString(null, CultureInfo.InvariantCulture)
? ((IFormattable)defaultValue).ToString(null, CultureInfo.InvariantCulture)
: Invariant($"{defaultValue}");
Log.Trace(Invariant($"Config.GetValue(): {key} - Using default value: {defaultValueString}"));
if (Log.DebuggingEnabled)
{
Log.Debug(Invariant($"Config.GetValue(): {key} - Using default value: {defaultValueString}"));
}
return defaultValue;
}
@@ -255,22 +261,22 @@ namespace QuantConnect.Configuration
if (type.IsEnum)
{
return (T) Enum.Parse(type, value, true);
return (T)Enum.Parse(type, value, true);
}
if (typeof(IConvertible).IsAssignableFrom(type))
{
return (T) Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
return (T)Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
}
// try and find a static parse method
try
{
var parse = type.GetMethod("Parse", new[]{typeof(string)});
var parse = type.GetMethod("Parse", new[] { typeof(string) });
if (parse != null)
{
var result = parse.Invoke(null, new object[] {value});
return (T) result;
var result = parse.Invoke(null, new object[] { value });
return (T)result;
}
}
catch (Exception err)
@@ -381,7 +387,7 @@ namespace QuantConnect.Configuration
var environments = config["environments"];
if (!(environments is JObject)) continue;
var settings = ((JObject) environments).SelectToken(env);
var settings = ((JObject)environments).SelectToken(env);
if (settings == null) continue;
// copy values for the selected environment to the root
@@ -395,7 +401,7 @@ namespace QuantConnect.Configuration
var jProperty = clone.Property(path);
if (jProperty != null) jProperty.Remove();
var value = (token is JProperty ? ((JProperty) token).Value : token).ToString();
var value = (token is JProperty ? ((JProperty)token).Value : token).ToString();
clone.Add(path, value);
}
}

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Configuration</RootNamespace>
<AssemblyName>QuantConnect.Configuration</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>

File diff suppressed because it is too large Load Diff

View File

@@ -22,11 +22,11 @@ RUN if [ "$(uname -m)" = "aarch64" ]; then \
chmod +x /usr/local/bin/tini
# Install clr-loader for PythonNet
RUN pip install --no-cache-dir clr-loader==0.1.6
RUN pip install --no-cache-dir clr-loader==0.2.9
# Install .NET Interactive to support C# in Jupyter notebooks
ENV PATH="${PATH}:/root/.dotnet/tools"
RUN dotnet tool install -g --no-cache --version 1.0.607001 --add-source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" Microsoft.dotnet-interactive && \
RUN dotnet tool install -g --no-cache --version 1.0.661703 --add-source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" Microsoft.dotnet-interactive && \
dotnet interactive jupyter install
# Setting some environment variables

View File

@@ -52,7 +52,7 @@ RUN pip install --no-cache-dir \
wrapt==1.17.3 \
astropy==7.2.0 \
beautifulsoup4==4.14.3 \
dill==0.4.0 \
dill==0.3.8 \
jsonschema==4.25.1 \
lxml==6.0.2 \
msgpack==1.1.2 \
@@ -167,12 +167,12 @@ RUN pip install --no-cache-dir \
hurst==0.0.5 \
numerapi==2.21.0 \
pymdptoolbox==4.0-b3 \
panel==1.8.4 \
panel==1.7.5 \
hvplot==0.12.2 \
line-profiler==5.0.0 \
py-heat==0.0.6 \
py-heat-magic==0.0.2 \
bokeh==3.8.1 \
bokeh==3.6.3 \
river==0.21.0 \
stumpy==1.13.0 \
pyvinecopulib==0.6.5 \
@@ -205,7 +205,7 @@ RUN pip install --no-cache-dir \
pymannkendall==1.4.3 \
Pyomo==6.9.5 \
gpflow==2.10.0 \
pyarrow==21.0.0 \
pyarrow==19.0.1 \
dwave-ocean-sdk==9.2.0 \
chardet==5.2.0 \
stable-baselines3==2.7.1 \
@@ -234,13 +234,13 @@ RUN pip install --no-cache-dir \
Riskfolio-Lib==7.0.1 \
fuzzy-c-means==1.7.2 \
EMD-signal==1.9.0 \
dask[complete]==2025.12.0 \
dask[complete]==2025.7.0 \
nolds==0.6.2 \
feature-engine==1.9.3 \
pytorch-tabnet==4.1.0 \
opencv-contrib-python-headless==4.11.0.86 \
POT==0.9.6.post1 \
datasets==4.4.2 \
datasets==3.6.0 \
scikeras==0.13.0 \
accelerate==1.12.0 \
peft==0.18.0 \
@@ -288,7 +288,7 @@ RUN pip install --no-cache-dir \
ydf==0.13.0 \
wurlitzer==3.1.1 \
statsforecast==2.0.3 \
holoviews==1.22.1 \
holoviews==1.20.2 \
faiss-cpu==1.13.1 \
ImageIO==2.37.2 \
lifelines==0.30.0 \
@@ -410,10 +410,10 @@ RUN apt-get update && apt-get -y install libasound2 libnss3 libnspr4 && apt-get
rm ibgateway-latest-standalone-linux-x64.v10.39.1f.sh
# Install dotnet sdk & runtime
RUN add-apt-repository ppa:dotnet/backports && apt-get update && apt-get install -y dotnet-sdk-10.0 dotnet-sdk-9.0 && \
apt-get clean && apt-get autoclean && apt-get autoremove --purge -y && rm -rf /var/lib/apt/lists/* && dotnet new globaljson --sdk-version 9.0.112
RUN add-apt-repository ppa:dotnet/backports && apt-get update && apt-get install -y dotnet-sdk-10.0 && \
apt-get clean && apt-get autoclean && apt-get autoremove --purge -y && rm -rf /var/lib/apt/lists/*
# label definitions
LABEL strict_python_version=3.11.11
LABEL python_version=3.11
LABEL target_framework=net9.0
LABEL target_framework=net10.0

View File

@@ -53,7 +53,7 @@ RUN pip install --no-cache-dir \
wrapt==1.17.3 \
astropy==7.2.0 \
beautifulsoup4==4.14.3 \
dill==0.4.0 \
dill==0.3.8 \
jsonschema==4.25.1 \
lxml==6.0.2 \
msgpack==1.1.2 \
@@ -147,11 +147,11 @@ RUN pip install --no-cache-dir \
hurst==0.0.5 \
numerapi==2.21.0 \
pymdptoolbox==4.0-b3 \
panel==1.8.4 \
panel==1.7.5 \
hvplot==0.12.2 \
py-heat==0.0.6 \
py-heat-magic==0.0.2 \
bokeh==3.8.1 \
bokeh==3.6.3 \
river==0.21.0 \
stumpy==1.13.0 \
pyvinecopulib==0.6.5 \
@@ -184,7 +184,7 @@ RUN pip install --no-cache-dir \
pymannkendall==1.4.3 \
Pyomo==6.9.5 \
gpflow==2.10.0 \
pyarrow==21.0.0 \
pyarrow==19.0.1 \
dwave-ocean-sdk==9.2.0 \
chardet==5.2.0 \
stable-baselines3==2.7.1 \
@@ -203,7 +203,7 @@ RUN pip install --no-cache-dir \
pytorch-tabnet==4.1.0 \
opencv-contrib-python-headless==4.11.0.86 \
POT==0.9.6.post1 \
datasets==4.4.2 \
datasets==3.6.0 \
scikeras==0.13.0 \
contourpy==1.3.3 \
click==8.2.1
@@ -267,11 +267,11 @@ RUN wget -q https://cdn.quantconnect.com/fonts/foundation.zip && unzip -q founda
ENV PATH="/root/.dotnet:${PATH}"
RUN wget https://dot.net/v1/dotnet-install.sh && \
chmod 777 dotnet-install.sh && \
./dotnet-install.sh -c 10.0 && ./dotnet-install.sh -c 9.0 && \
rm dotnet-install.sh && dotnet new globaljson --sdk-version 9.0.308
./dotnet-install.sh -c 10.0 && \
rm dotnet-install.sh
ENV DOTNET_ROOT="/root/.dotnet"
# label definitions
LABEL strict_python_version=3.11.11
LABEL python_version=3.11
LABEL target_framework=net9.0
LABEL target_framework=net10.0

View File

@@ -6,7 +6,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>QuantConnect.DownloaderDataProvider.Launcher</RootNamespace>
<AssemblyName>QuantConnect.DownloaderDataProvider.Launcher</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Lean.Engine</RootNamespace>
<AssemblyName>QuantConnect.Lean.Engine</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<PublishUrl>publish\</PublishUrl>
@@ -41,7 +41,7 @@
<Message Text="SelectedOptimization $(SelectedOptimization)" Importance="high" />
</Target>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="fasterflect" Version="3.0.0" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />

134
Indicators/Covariance.cs Normal file
View File

@@ -0,0 +1,134 @@
/*
* 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 QuantConnect.Data.Market;
using MathNet.Numerics.Statistics;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the Covariance of two assets using the given Look-Back period.
/// The Covariance of two assets is a measure of their co-movement.
/// </summary>
public class Covariance : DualSymbolIndicator<IBaseDataBar>
{
/// <summary>
/// RollingWindow of returns of the target symbol in the given period
/// </summary>
private readonly RollingWindow<double> _targetReturns;
/// <summary>
/// RollingWindow of returns of the reference symbol in the given period
/// </summary>
private readonly RollingWindow<double> _referenceReturns;
/// <summary>
/// Gets a flag indicating when the indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _targetReturns.IsReady && _referenceReturns.IsReady;
/// <summary>
/// Creates a new Covariance indicator with the specified name, target, reference,
/// and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
public Covariance(string name, Symbol targetSymbol, Symbol referenceSymbol, int period)
: base(name, targetSymbol, referenceSymbol, 2)
{
// Assert the period is greater than two, otherwise the covariance can not be computed
if (period < 2)
{
throw new ArgumentException($"Period parameter for Covariance indicator must be greater than 2 but was {period}.");
}
_targetReturns = new RollingWindow<double>(period);
_referenceReturns = new RollingWindow<double>(period);
WarmUpPeriod += (period - 2) + 1;
}
/// <summary>
/// Creates a new Covariance indicator with the specified target, reference,
/// and period values
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
public Covariance(Symbol targetSymbol, Symbol referenceSymbol, int period)
: this($"COV({period})", targetSymbol, referenceSymbol, period)
{
}
/// <summary>
/// Creates a new Covariance indicator with the specified name, period, target and
/// reference values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <remarks>Constructor overload for backward compatibility.</remarks>
public Covariance(string name, int period, Symbol targetSymbol, Symbol referenceSymbol)
: this(name, targetSymbol, referenceSymbol, period)
{
}
/// <summary>
/// Computes the returns with the new given data point and the last given data point
/// </summary>
/// <param name="rollingWindow">The collection of data points from which we want
/// to compute the return</param>
/// <returns>The returns with the new given data point</returns>
private static double GetNewReturn(IReadOnlyWindow<IBaseDataBar> rollingWindow)
{
return (double)(rollingWindow[0].Close.SafeDivision(rollingWindow[1].Close) - 1);
}
/// <summary>
/// Computes the covariance value of the target in relation with the reference
/// using the target and reference returns
/// </summary>
protected override decimal ComputeIndicator()
{
if (TargetDataPoints.IsReady)
{
_targetReturns.Add(GetNewReturn(TargetDataPoints));
}
if (ReferenceDataPoints.IsReady)
{
_referenceReturns.Add(GetNewReturn(ReferenceDataPoints));
}
var covarianceComputed = _targetReturns.Covariance(_referenceReturns);
// Avoid division with NaN or by zero
return (decimal)(!covarianceComputed.IsNaNOrZero() ? covarianceComputed : 0);
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_targetReturns.Reset();
_referenceReturns.Reset();
base.Reset();
}
}
}

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Indicators</RootNamespace>
<AssemblyName>QuantConnect.Indicators</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
@@ -31,7 +31,7 @@
<Message Text="SelectedOptimization $(SelectedOptimization)" Importance="high" />
</Target>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -5,7 +5,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>QuantConnect.Lean.Launcher</RootNamespace>
<AssemblyName>QuantConnect.Lean.Launcher</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>

View File

@@ -755,6 +755,21 @@
"real-time-handler": "QuantConnect.Lean.Engine.RealTime.LiveTradingRealTimeHandler",
"transaction-handler": "QuantConnect.Lean.Engine.TransactionHandlers.BrokerageTransactionHandler",
"history-provider": [ "BrokerageHistoryProvider", "SubscriptionDataReaderHistoryProvider" ]
},
// defines the 'live-dydx' environment
"live-dydx": {
"live-mode": true,
// real brokerage implementations require the BrokerageTransactionHandler
"live-mode-brokerage": "dYdXBrokerage",
"data-queue-handler": [ "dYdXBrokerage" ],
"setup-handler": "QuantConnect.Lean.Engine.Setup.BrokerageSetupHandler",
"result-handler": "QuantConnect.Lean.Engine.Results.LiveTradingResultHandler",
"data-feed-handler": "QuantConnect.Lean.Engine.DataFeeds.LiveTradingDataFeed",
"real-time-handler": "QuantConnect.Lean.Engine.RealTime.LiveTradingRealTimeHandler",
"transaction-handler": "QuantConnect.Lean.Engine.TransactionHandlers.BrokerageTransactionHandler",
"history-provider": [ "BrokerageHistoryProvider", "SubscriptionDataReaderHistoryProvider" ]
}
}
}
}

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Logging</RootNamespace>
<AssemblyName>QuantConnect.Logging</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Messaging</RootNamespace>
<AssemblyName>QuantConnect.Messaging</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>

View File

@@ -5,7 +5,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>QuantConnect.Optimizer.Launcher</RootNamespace>
<AssemblyName>QuantConnect.Optimizer.Launcher</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Optimizer</RootNamespace>
<AssemblyName>QuantConnect.Optimizer</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Queues</RootNamespace>
<AssemblyName>QuantConnect.Queues</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<DocumentationFile>bin\$(Configuration)\QuantConnect.Queues.xml</DocumentationFile>

View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Exe</OutputType>
<RootNamespace>QuantConnect.Report</RootNamespace>
<AssemblyName>QuantConnect.Report</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<DocumentationFile>bin\$(Configuration)\QuantConnect.Report.xml</DocumentationFile>
@@ -39,7 +39,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="Deedle" Version="2.1.0" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />

View File

@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Research</RootNamespace>
<AssemblyName>QuantConnect.Research</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<OutputPath>bin\$(Configuration)\</OutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -34,7 +34,7 @@
<PackageReference Include="Plotly.NET" Version="5.1.0" />
<PackageReference Include="Plotly.NET.CSharp" Version="0.13.0" />
<PackageReference Include="Plotly.NET.Interactive" Version="5.0.0" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="NodaTime" Version="3.0.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -25,7 +25,7 @@ from pythonnet import set_runtime
# symlink and the directory start.py is stored in is not necessarily the
# current working directory. We therefore construct the absolute path to the
# start.py file, and find the runtimeconfig.json relative to that.
set_runtime(clr_loader.get_coreclr(os.path.join(os.path.dirname(os.path.realpath(__file__)), "QuantConnect.Lean.Launcher.runtimeconfig.json")))
set_runtime(clr_loader.get_coreclr(runtime_config=os.path.join(os.path.dirname(os.path.realpath(__file__)), "QuantConnect.Lean.Launcher.runtimeconfig.json")))
from AlgorithmImports import *

View File

@@ -453,6 +453,37 @@ namespace QuantConnect.Tests.Common.Securities
}
}
[Test]
public void EnsureCurrencyDataFeedForCryptoCurrency_CryptoFuturesFirst_When_dYdX()
{
var book = new CashBook
{
{Currencies.USD, new Cash(Currencies.USD, 100, 1) },
{"BTC", new Cash("BTC", 100, 6000) },
{"ETH", new Cash("ETH", 100, 290) }
};
var subscriptions = new SubscriptionManager(NullTimeKeeper.Instance);
var dataManager = new DataManagerStub(TimeKeeper);
subscriptions.SetDataManager(dataManager);
var securities = new SecurityManager(TimeKeeper);
var marketMapWithdYdX = MarketMap.ToDictionary();
marketMapWithdYdX[SecurityType.CryptoFuture] = Market.dYdX;
book.EnsureCurrencyDataFeeds(securities, subscriptions, marketMapWithdYdX, SecurityChanges.None, dataManager.SecurityService);
var symbols = dataManager.SubscriptionManagerSubscriptions.Select(sdc => sdc.Symbol).ToHashSet();
Assert.IsTrue(symbols.Contains(Symbol.Create("BTCUSD", SecurityType.CryptoFuture, Market.dYdX)));
Assert.IsTrue(symbols.Contains(Symbol.Create("ETHUSD", SecurityType.CryptoFuture, Market.dYdX)));
foreach (var subscription in subscriptions.Subscriptions)
{
Assert.AreEqual(subscription.Symbol.SecurityType, SecurityType.CryptoFuture);
}
}
[Test]
public void UpdateModifiesConversionRateAsInvertedValue()
{

View File

@@ -62,12 +62,14 @@ namespace QuantConnect.Tests.Common.Securities
Assert.AreEqual(symbols[7], filtered[4]);
}
[Test]
public void FiltersOutWeeklysByDefault()
[TestCase(false, 6)]
[TestCase(true, 2)]
public void FutureContractFiltering(bool standardsOnly, int expectedCount)
{
var time = new DateTime(2016, 02, 17, 13, 0, 0);
Func<FutureFilterUniverse, FutureFilterUniverse> universeFunc = universe => universe;
Func<FutureFilterUniverse, FutureFilterUniverse> universeFunc = universe =>
standardsOnly ? universe.StandardsOnly() : universe;
Func<IDerivativeSecurityFilterUniverse<FutureUniverse>, IDerivativeSecurityFilterUniverse<FutureUniverse>> func =
universe => universeFunc(universe as FutureFilterUniverse).ApplyTypesFilter();
@@ -75,19 +77,33 @@ namespace QuantConnect.Tests.Common.Securities
var filter = new FuncSecurityDerivativeFilter<FutureUniverse>(func);
var symbols = new[]
{
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(0)), // 0 Standard!!
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(1)), // 1
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(2)), // 2
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(8)), // 8
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(16)), // 16
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(28)), // 28 Standard!!
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(0)), // Standard
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(1)),
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(2)),
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(8)),
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(16)),
Symbol.CreateFuture("VX", Market.CFE, time.AddDays(28)), // Standard
};
var data = symbols.Select(x => new FutureUniverse() { Symbol = x });
var filtered = filter.Filter(new FutureFilterUniverse(data, time)).Select(x => x.Symbol).ToList();
Assert.AreEqual(2, filtered.Count);
Assert.AreEqual(symbols[0], filtered[0]);
Assert.AreEqual(symbols[5], filtered[1]);
Assert.AreEqual(expectedCount, filtered.Count);
if (standardsOnly)
{
// When StandardsOnly, only Standards should be returned
Assert.AreEqual(symbols[0], filtered[0]);
Assert.AreEqual(symbols[5], filtered[1]);
}
else
{
// By default both Standards and Weeklys are returned
for (int i = 0; i < 6; i++)
{
Assert.AreEqual(symbols[i], filtered[i]);
}
}
}
[Test]

View File

@@ -107,6 +107,27 @@ namespace QuantConnect.Tests.Common.Securities.FutureOption
[TestCase("6N", Market.CME, "202511", "20251107", "20251215")]
[TestCase("6N", Market.CME, "202512", "20251205", "20251215")]
[TestCase("6N", Market.CME, "202601", "20260109", "20260316")]
[TestCase("6N", Market.CME, "202601", "20260109", "20260316")]
[TestCase("6N", Market.CME, "202602", "20260206", "20260316")]
[TestCase("6N", Market.CME, "202604", "20260403", "20260615")]
[TestCase("6B", Market.CME, "202601", "20260109", "20260316")]
[TestCase("6B", Market.CME, "202602", "20260206", "20260316")]
[TestCase("6B", Market.CME, "202603", "20260306", "20260316")]
[TestCase("6C", Market.CME, "202601", "20260109", "20260317")]
[TestCase("6C", Market.CME, "202602", "20260206", "20260317")]
[TestCase("6C", Market.CME, "202603", "20260306", "20260317")]
[TestCase("6J", Market.CME, "202601", "20260109", "20260316")]
[TestCase("6J", Market.CME, "202602", "20260206", "20260316")]
[TestCase("6J", Market.CME, "202603", "20260306", "20260316")]
[TestCase("6S", Market.CME, "202601", "20260109", "20260316")]
[TestCase("6S", Market.CME, "202602", "20260206", "20260316")]
[TestCase("6S", Market.CME, "202603", "20260306", "20260316")]
[TestCase("6E", Market.CME, "202601", "20260109", "20260316")]
[TestCase("6E", Market.CME, "202602", "20260206", "20260316")]
[TestCase("6E", Market.CME, "202603", "20260306", "20260316")]
[TestCase("6M", Market.CME, "202604", "20260403", "20260615")]
[TestCase("6M", Market.CME, "202605", "20260508", "20260615")]
[TestCase("6M", Market.CME, "202606", "20260605", "20260615")]
[TestCase("6A", Market.CME, "202601", "20260109", "20260316", Description = "Quarterly contract : Mar")]
[TestCase("6A", Market.CME, "202602", "20260206", "20260316", Description = "Quarterly contract : Mar")]
[TestCase("6A", Market.CME, "202603", "20260306", "20260316", Description = "Quarterly contract : Mar")]

View File

@@ -39,16 +39,23 @@ namespace QuantConnect.Tests.Common.Securities.FutureOption
[TestCase("6A", Market.CME, 2021, 10, 05, 2021, 12, 13, false)]
[TestCase("6A", Market.CME, 2021, 11, 05, 2021, 12, 13, false)]
[TestCase("6A", Market.CME, 2021, 12, 05, 2021, 12, 13, false)]
[TestCase("6B", Market.CME, 2025, 09, 05, 2025, 09, 15, false)]
[TestCase("6B", Market.CME, 2025, 12, 05, 2025, 12, 15, false)]
[TestCase("6C", Market.CME, 2025, 09, 05, 2025, 09, 16, false)]
[TestCase("6C", Market.CME, 2025, 12, 05, 2025, 12, 16, false)]
[TestCase("6E", Market.CME, 2025, 09, 05, 2025, 09, 15, false)]
[TestCase("6E", Market.CME, 2025, 12, 05, 2025, 12, 15, false)]
[TestCase("6J", Market.CME, 2025, 09, 05, 2025, 09, 15, false)]
[TestCase("6J", Market.CME, 2025, 12, 05, 2025, 12, 15, false)]
[TestCase("6S", Market.CME, 2025, 09, 05, 2025, 09, 15, false)]
[TestCase("6S", Market.CME, 2025, 12, 05, 2025, 12, 15, false)]
[TestCase("6N", Market.CME, 2021, 01, 09, 2021, 03, 15, false)]
[TestCase("6B", Market.CME, 2021, 02, 06, 2021, 03, 15, false)]
[TestCase("6B", Market.CME, 2021, 09, 05, 2021, 09, 13, false)]
[TestCase("6B", Market.CME, 2021, 12, 05, 2021, 12, 13, false)]
[TestCase("6C", Market.CME, 2021, 01, 09, 2021, 03, 16, false)]
[TestCase("6C", Market.CME, 2021, 09, 05, 2021, 09, 14, false)]
[TestCase("6C", Market.CME, 2021, 12, 05, 2021, 12, 14, false)]
[TestCase("6E", Market.CME, 2021, 09, 05, 2021, 09, 13, false)]
[TestCase("6E", Market.CME, 2021, 12, 05, 2021, 12, 13, false)]
[TestCase("6E", Market.CME, 2021, 01, 09, 2021, 03, 15, false)]
[TestCase("6M", Market.CME, 2021, 04, 03, 2021, 06, 14, false)]
[TestCase("6J", Market.CME, 2021, 09, 05, 2021, 09, 13, false)]
[TestCase("6J", Market.CME, 2021, 12, 05, 2021, 12, 13, false)]
[TestCase("6J", Market.CME, 2021, 02, 06, 2021, 03, 15, false)]
[TestCase("6S", Market.CME, 2021, 09, 05, 2021, 09, 13, false)]
[TestCase("6S", Market.CME, 2021, 12, 05, 2021, 12, 13, false)]
[TestCase("6S", Market.CME, 2021, 02, 06, 2021, 03, 15, false)]
[TestCase("ZC", Market.CBOT, 2031, 12, 26, 2031, 12, 26, true)]
[TestCase("ZS", Market.CBOT, 2034, 12, 22, 2034, 12, 22, true)]
[TestCase("ZW", Market.CBOT, 2036, 12, 26, 2036, 12, 26, true)]

View File

@@ -319,6 +319,20 @@ namespace QuantConnect.Tests.Common.Securities.Futures
Assert.AreEqual(new DateTime(2025, 2, 14), expiryDate.Date);
}
[TestCase(QuantConnect.Securities.Futures.Indices.NASDAQ100EMini, "20260302", "20260320")]
[TestCase(QuantConnect.Securities.Futures.Indices.NASDAQ100EMini, "20260602", "20260618")]
public void ExpirationUsesHolidays(string symbol, string dateStr, string expectedDate)
{
var date = Time.ParseDate(dateStr);
var expected = Time.ParseDate(expectedDate);
var futureSymbol = GetFutureSymbol(symbol, date);
var func = FuturesExpiryFunctions.FuturesExpiryFunction(GetFutureSymbol(symbol));
var actual = func(futureSymbol.ID.Date);
Assert.AreEqual(expected, actual.Date, $"Failed for symbol: {symbol}. Date {dateStr}");
}
// 25th is a sunday
[TestCase(QuantConnect.Securities.Futures.Energy.MicroCrudeOilWTI, "20221001", "20220919")]
[TestCase(QuantConnect.Securities.Futures.Energy.CrudeOilWTI, "20221001", "20220920")]

View File

@@ -373,7 +373,7 @@ namespace QuantConnect.Tests.Common.Securities
var underlying = new Tick { Value = 10m, Time = new DateTime(2016, 12, 29) };
Func<OptionFilterUniverse, OptionFilterUniverse> universeFunc = universe => universe;
Func<OptionFilterUniverse, OptionFilterUniverse> universeFunc = universe => universe.StandardsOnly();
Func<IDerivativeSecurityFilterUniverse<OptionUniverse>, IDerivativeSecurityFilterUniverse<OptionUniverse>> func =
universe => universeFunc(universe as OptionFilterUniverse).ApplyTypesFilter();
@@ -418,7 +418,7 @@ namespace QuantConnect.Tests.Common.Securities
var underlying = new Tick { Value = 10m, Time = new DateTime(2016, 12, 29) };
Func<OptionFilterUniverse, OptionFilterUniverse> universeFunc = universe => universe;
Func<OptionFilterUniverse, OptionFilterUniverse> universeFunc = universe => universe.StandardsOnly();
Func<IDerivativeSecurityFilterUniverse<OptionUniverse>, IDerivativeSecurityFilterUniverse<OptionUniverse>> func =
universe => universeFunc(universe as OptionFilterUniverse).ApplyTypesFilter();

View File

@@ -320,6 +320,54 @@ namespace QuantConnect.Tests.Common.Util
Assert.AreEqual(201900, smartStream.GetInt32());
}
[Test]
public void GetInt64()
{
var stream = $"1588291200426000,0,1588291202486000{Environment.NewLine}1588291205550000{Environment.NewLine}".ToStream();
using var smartStream = new StreamReader(stream);
Assert.AreEqual(1588291200426000, smartStream.GetInt64());
Assert.AreEqual(0L, smartStream.GetInt64());
Assert.AreEqual(1588291202486000, smartStream.GetInt64());
Assert.AreEqual(1588291205550000, smartStream.GetInt64());
}
[Test]
public void GetNegativeInt64()
{
var stream = $"-1588291200426000,0,-1588291202486000{Environment.NewLine}-1588291205550000{Environment.NewLine}".ToStream();
using var smartStream = new StreamReader(stream);
Assert.AreEqual(-1588291200426000, smartStream.GetInt64());
Assert.AreEqual(0L, smartStream.GetInt64());
Assert.AreEqual(-1588291202486000, smartStream.GetInt64());
Assert.AreEqual(-1588291205550000, smartStream.GetInt64());
}
[Test]
public void GetInt64WithCarriageReturnAndLineFeed()
{
var stream = "1588291200426000,0,1588291202486000\r\n1588291205550000\r\n".ToStream();
using var smartStream = new StreamReader(stream);
Assert.AreEqual(1588291200426000, smartStream.GetInt64());
Assert.AreEqual(0L, smartStream.GetInt64());
Assert.AreEqual(1588291202486000, smartStream.GetInt64());
Assert.AreEqual(1588291205550000, smartStream.GetInt64());
}
[Test]
public void GetInt64WithLineFeed()
{
var stream = "1588291200426000,0,1588291202486000\n1588291205550000\n".ToStream();
using var smartStream = new StreamReader(stream);
Assert.AreEqual(1588291200426000, smartStream.GetInt64());
Assert.AreEqual(0L, smartStream.GetInt64());
Assert.AreEqual(1588291202486000, smartStream.GetInt64());
Assert.AreEqual(1588291205550000, smartStream.GetInt64());
}
[Parallelizable(ParallelScope.None)]
[TestCase(typeof(TradeBar), typeof(TradeBarTest), TickType.Trade)]
[TestCase(typeof(QuoteBar), typeof(QuoteBarTest), TickType.Quote)]

Some files were not shown because too many files have changed in this diff Show More