chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Algorithm;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
using QuantConnect.Algorithm.Framework.Selection;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
[TestFixture]
|
||||
public class BasePairsTradingAlphaModelTests : CommonAlphaModelTests
|
||||
{
|
||||
private const int _lookback = 15;
|
||||
private const Resolution _resolution = Resolution.Minute;
|
||||
|
||||
protected override int MaxSliceCount => 1500;
|
||||
|
||||
protected override IAlphaModel CreateCSharpAlphaModel()
|
||||
{
|
||||
return new BasePairsTradingAlphaModel(_lookback, _resolution);
|
||||
}
|
||||
|
||||
protected override void InitializeAlgorithm(QCAlgorithm algorithm)
|
||||
{
|
||||
algorithm.SetUniverseSelection(new ManualUniverseSelectionModel(
|
||||
Symbol.Create("AIG", SecurityType.Equity, Market.USA),
|
||||
Symbol.Create("BAC", SecurityType.Equity, Market.USA)));
|
||||
}
|
||||
|
||||
protected override string GetExpectedModelName(IAlphaModel model)
|
||||
{
|
||||
return $"{nameof(BasePairsTradingAlphaModel)}({_lookback},{_resolution},1)";
|
||||
}
|
||||
|
||||
protected override IAlphaModel CreatePythonAlphaModel()
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
dynamic model = Py.Import("BasePairsTradingAlphaModel").GetAttr("BasePairsTradingAlphaModel");
|
||||
var instance = model(_lookback, _resolution);
|
||||
return new AlphaModelPythonWrapper(instance);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<Insight> ExpectedInsights()
|
||||
{
|
||||
Assert.Ignore("The CommonAlphaModelTests need to be refactored to support multiple securities with different prices for each security");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
using QuantConnect.Algorithm.Framework.Portfolio;
|
||||
using QuantConnect.Algorithm.Framework.Selection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Lean.Engine.DataFeeds;
|
||||
using QuantConnect.Lean.Engine.HistoricalData;
|
||||
using QuantConnect.Securities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Algorithm;
|
||||
using QuantConnect.Python;
|
||||
using QuantConnect.Tests.Common.Data.UniverseSelection;
|
||||
using QuantConnect.Tests.Engine.DataFeeds;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a framework for testing alpha models.
|
||||
/// </summary>
|
||||
public abstract class CommonAlphaModelTests
|
||||
{
|
||||
protected QCAlgorithm Algorithm { get; set; }
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void Initialize()
|
||||
{
|
||||
PythonInitializer.Initialize();
|
||||
|
||||
Algorithm = new QCAlgorithm();
|
||||
Algorithm.PortfolioConstruction = new NullPortfolioConstructionModel();
|
||||
Algorithm.HistoryProvider = new SineHistoryProvider(Algorithm.Securities);
|
||||
Algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(Algorithm));
|
||||
InitializeAlgorithm(Algorithm);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Language.CSharp)]
|
||||
[TestCase(Language.Python)]
|
||||
public void AddAlphaModel(Language language)
|
||||
{
|
||||
IAlphaModel model;
|
||||
IAlphaModel model2 = null;
|
||||
IAlphaModel model3 = null;
|
||||
if (!TryCreateModel(language, out model)
|
||||
|| !TryCreateModel(language, out model2)
|
||||
|| !TryCreateModel(language, out model3))
|
||||
{
|
||||
Assert.Ignore($"Ignore {GetType().Name}: Could not create {language} model.");
|
||||
}
|
||||
|
||||
// Set the alpha model
|
||||
Algorithm.SetAlpha(model);
|
||||
Algorithm.AddAlpha(model2);
|
||||
Algorithm.AddAlpha(model3);
|
||||
Algorithm.SetUniverseSelection(new ManualUniverseSelectionModel());
|
||||
|
||||
var changes = SecurityChangesTests.CreateNonInternal(AddedSecurities, RemovedSecurities);
|
||||
Algorithm.OnFrameworkSecuritiesChanged(changes);
|
||||
|
||||
var actualInsights = new List<Insight>();
|
||||
Algorithm.InsightsGenerated += (s, e) => actualInsights.AddRange(e.Insights);
|
||||
|
||||
var expectedInsights = ExpectedInsights().ToList();
|
||||
|
||||
var consolidators = Algorithm.Securities.SelectMany(kvp => kvp.Value.Subscriptions).SelectMany(x => x.Consolidators);
|
||||
var slices = CreateSlices();
|
||||
|
||||
foreach (var slice in slices.ToList())
|
||||
{
|
||||
Algorithm.SetDateTime(slice.Time);
|
||||
|
||||
foreach (var symbol in slice.Keys)
|
||||
{
|
||||
var data = slice[symbol];
|
||||
Algorithm.Securities[symbol].SetMarketPrice(data);
|
||||
|
||||
foreach (var consolidator in consolidators)
|
||||
{
|
||||
consolidator.Update(data);
|
||||
}
|
||||
}
|
||||
|
||||
Algorithm.OnFrameworkData(slice);
|
||||
}
|
||||
|
||||
Assert.AreEqual(expectedInsights.Count * 3, actualInsights.Count);
|
||||
|
||||
for (var i = 0; i < actualInsights.Count; i = i + 3)
|
||||
{
|
||||
var expected = expectedInsights[i / 3];
|
||||
for (int j = i; j < 3; j++)
|
||||
{
|
||||
var actual = actualInsights[j];
|
||||
Assert.AreEqual(expected.Symbol, actual.Symbol);
|
||||
Assert.AreEqual(expected.Type, actual.Type);
|
||||
Assert.AreEqual(expected.Direction, actual.Direction);
|
||||
Assert.LessOrEqual(expected.Period, actual.Period); // It can be canceled and discarded early
|
||||
Assert.AreEqual(expected.Magnitude, actual.Magnitude);
|
||||
Assert.AreEqual(expected.Confidence, actual.Confidence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Language.CSharp)]
|
||||
[TestCase(Language.Python)]
|
||||
public void InsightsGenerationTest(Language language)
|
||||
{
|
||||
IAlphaModel model;
|
||||
if (!TryCreateModel(language, out model))
|
||||
{
|
||||
Assert.Ignore($"Ignore {GetType().Name}: Could not create {language} model.");
|
||||
}
|
||||
|
||||
// Set the alpha model
|
||||
Algorithm.SetAlpha(model);
|
||||
Algorithm.SetUniverseSelection(new ManualUniverseSelectionModel());
|
||||
|
||||
var changes = SecurityChangesTests.CreateNonInternal(AddedSecurities, RemovedSecurities);
|
||||
Algorithm.OnFrameworkSecuritiesChanged(changes);
|
||||
|
||||
var actualInsights = new List<Insight>();
|
||||
Algorithm.InsightsGenerated += (s, e) => actualInsights.AddRange(e.Insights);
|
||||
|
||||
var expectedInsights = ExpectedInsights().ToList();
|
||||
|
||||
var consolidators = Algorithm.Securities.SelectMany(kvp => kvp.Value.Subscriptions).SelectMany(x => x.Consolidators);
|
||||
var slices = CreateSlices();
|
||||
|
||||
foreach (var slice in slices.ToList())
|
||||
{
|
||||
Algorithm.SetDateTime(slice.Time);
|
||||
|
||||
foreach (var symbol in slice.Keys)
|
||||
{
|
||||
var data = slice[symbol];
|
||||
Algorithm.Securities[symbol].SetMarketPrice(data);
|
||||
|
||||
foreach (var consolidator in consolidators)
|
||||
{
|
||||
consolidator.Update(data);
|
||||
}
|
||||
}
|
||||
|
||||
Algorithm.OnFrameworkData(slice);
|
||||
}
|
||||
|
||||
Assert.AreEqual(expectedInsights.Count, actualInsights.Count);
|
||||
|
||||
for (var i = 0; i < actualInsights.Count; i++)
|
||||
{
|
||||
var actual = actualInsights[i];
|
||||
var expected = expectedInsights[i];
|
||||
Assert.AreEqual(expected.Symbol, actual.Symbol);
|
||||
Assert.AreEqual(expected.Type, actual.Type);
|
||||
Assert.AreEqual(expected.Direction, actual.Direction);
|
||||
Assert.LessOrEqual(expected.Period, actual.Period); // It can be canceled and discarded early
|
||||
Assert.AreEqual(expected.Magnitude, actual.Magnitude);
|
||||
Assert.AreEqual(expected.Confidence, actual.Confidence);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Language.CSharp)]
|
||||
[TestCase(Language.Python)]
|
||||
public void AddedSecuritiesTest(Language language)
|
||||
{
|
||||
IAlphaModel model;
|
||||
if (!TryCreateModel(language, out model))
|
||||
{
|
||||
Assert.Ignore($"Ignore {GetType().Name}: Could not create {language} model.");
|
||||
}
|
||||
|
||||
var changes = SecurityChangesTests.CreateNonInternal(AddedSecurities, RemovedSecurities);
|
||||
|
||||
Assert.DoesNotThrow(() => model.OnSecuritiesChanged(Algorithm, changes));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Language.CSharp)]
|
||||
[TestCase(Language.Python)]
|
||||
public void RemovedSecuritiesTest(Language language)
|
||||
{
|
||||
IAlphaModel model;
|
||||
if (!TryCreateModel(language, out model))
|
||||
{
|
||||
Assert.Ignore($"Ignore {GetType().Name}: Could not create {language} model.");
|
||||
}
|
||||
|
||||
var removedSecurities = Algorithm.Securities.Values;
|
||||
|
||||
// We have to add some security if we then want to remove it, that's why we cannot use here
|
||||
// RemovedSecurities, because it doesn't contain any security
|
||||
var changes = SecurityChangesTests.CreateNonInternal(removedSecurities, AddedSecurities);
|
||||
|
||||
Assert.DoesNotThrow(() => model.OnSecuritiesChanged(Algorithm, changes));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Language.CSharp)]
|
||||
[TestCase(Language.Python)]
|
||||
public void ModelNameTest(Language language)
|
||||
{
|
||||
IAlphaModel model;
|
||||
if (!TryCreateModel(language, out model))
|
||||
{
|
||||
Assert.Ignore($"Ignore {GetType().Name}: Could not create {language} model.");
|
||||
}
|
||||
|
||||
var actual = model.GetModelName();
|
||||
var expected = GetExpectedModelName(model);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new instance of the alpha model to test
|
||||
/// </summary>
|
||||
protected abstract IAlphaModel CreateCSharpAlphaModel();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new instance of the alpha model to test
|
||||
/// </summary>
|
||||
protected abstract IAlphaModel CreatePythonAlphaModel();
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerable with the expected insights
|
||||
/// </summary>
|
||||
protected abstract IEnumerable<Insight> ExpectedInsights();
|
||||
|
||||
/// <summary>
|
||||
/// List of securities to be added to the model
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<Security> AddedSecurities => Algorithm.Securities.Values;
|
||||
|
||||
/// <summary>
|
||||
/// List of securities to be removed to the model
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<Security> RemovedSecurities => Enumerable.Empty<Security>();
|
||||
|
||||
/// <summary>
|
||||
/// To be override for model types that implement <see cref="INamedModel"/>
|
||||
/// </summary>
|
||||
protected abstract string GetExpectedModelName(IAlphaModel model);
|
||||
|
||||
/// <summary>
|
||||
/// Provides derived types a chance to initialize anything special they require
|
||||
/// </summary>
|
||||
protected virtual void InitializeAlgorithm(QCAlgorithm algorithm)
|
||||
{
|
||||
Algorithm.SetStartDate(2018, 1, 4);
|
||||
Algorithm.AddEquity(Symbols.SPY.Value, Resolution.Daily);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an enumerable of Slice to update the alpha model
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<Slice> CreateSlices()
|
||||
{
|
||||
var timeSliceFactory = new TimeSliceFactory(TimeZones.NewYork);
|
||||
var changes = SecurityChanges.None;
|
||||
var sliceDateTimes = GetSliceDateTimes(MaxSliceCount);
|
||||
|
||||
for (var i = 0; i < sliceDateTimes.Count; i++)
|
||||
{
|
||||
var utcDateTime = sliceDateTimes[i];
|
||||
|
||||
var packets = new List<DataFeedPacket>();
|
||||
|
||||
// TODO : Give securities different values -- will require updating all derived types
|
||||
var last = Convert.ToDecimal(100 + 10 * Math.Sin(Math.PI * i / 180.0));
|
||||
var high = last * 1.005m;
|
||||
var low = last / 1.005m;
|
||||
foreach (var kvp in Algorithm.Securities)
|
||||
{
|
||||
var security = kvp.Value;
|
||||
var exchange = security.Exchange.Hours;
|
||||
var configs = Algorithm.SubscriptionManager.SubscriptionDataConfigService
|
||||
.GetSubscriptionDataConfigs(security.Symbol);
|
||||
var extendedMarket = configs.IsExtendedMarketHours();
|
||||
var localDateTime = utcDateTime.ConvertFromUtc(exchange.TimeZone);
|
||||
if (!exchange.IsOpen(localDateTime, extendedMarket))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var configuration = security.Subscriptions.FirstOrDefault();
|
||||
var period = configs.GetHighestResolution().ToTimeSpan();
|
||||
var time = (utcDateTime - period).ConvertFromUtc(configuration.DataTimeZone);
|
||||
var tradeBar = new TradeBar(time, security.Symbol, last, high, low, last, 1000, period);
|
||||
packets.Add(new DataFeedPacket(security, configuration, new List<BaseData> { tradeBar }));
|
||||
}
|
||||
|
||||
if (packets.Count > 0)
|
||||
{
|
||||
yield return timeSliceFactory.Create(utcDateTime, packets, changes, new Dictionary<Universe, BaseDataCollection>()).Slice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set up the HistoryProvider for algorithm
|
||||
/// </summary>
|
||||
protected void SetUpHistoryProvider()
|
||||
{
|
||||
Algorithm.HistoryProvider = new SubscriptionDataReaderHistoryProvider();
|
||||
Algorithm.HistoryProvider.Initialize(new HistoryProviderInitializeParameters(
|
||||
null,
|
||||
null,
|
||||
TestGlobals.DataProvider,
|
||||
TestGlobals.DataCacheProvider,
|
||||
TestGlobals.MapFileProvider,
|
||||
TestGlobals.FactorFileProvider,
|
||||
null,
|
||||
false,
|
||||
new DataPermissionManager(),
|
||||
Algorithm.ObjectStore,
|
||||
Algorithm.Settings));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum number of slice objects to generate
|
||||
/// </summary>
|
||||
protected virtual int MaxSliceCount => 360;
|
||||
|
||||
private List<DateTime> GetSliceDateTimes(int maxCount)
|
||||
{
|
||||
var i = 0;
|
||||
var sliceDateTimes = new List<DateTime>();
|
||||
var utcDateTime = Algorithm.StartDate;
|
||||
|
||||
while (sliceDateTimes.Count < maxCount)
|
||||
{
|
||||
foreach (var kvp in Algorithm.Securities)
|
||||
{
|
||||
var security = kvp.Value;
|
||||
var configs = Algorithm.SubscriptionManager.SubscriptionDataConfigService
|
||||
.GetSubscriptionDataConfigs(security.Symbol);
|
||||
var resolution = configs.GetHighestResolution().ToTimeSpan();
|
||||
utcDateTime = utcDateTime.Add(resolution);
|
||||
if (resolution == Time.OneDay && utcDateTime.TimeOfDay == TimeSpan.Zero)
|
||||
{
|
||||
utcDateTime = utcDateTime.AddHours(17);
|
||||
}
|
||||
var exchange = security.Exchange.Hours;
|
||||
var extendedMarket = configs.IsExtendedMarketHours();
|
||||
var localDateTime = utcDateTime.ConvertFromUtc(exchange.TimeZone);
|
||||
if (exchange.IsOpen(localDateTime, extendedMarket))
|
||||
{
|
||||
sliceDateTimes.Add(utcDateTime);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return sliceDateTimes;
|
||||
}
|
||||
|
||||
private bool TryCreateModel(Language language, out IAlphaModel model)
|
||||
{
|
||||
model = default(IAlphaModel);
|
||||
|
||||
switch (language)
|
||||
{
|
||||
case Language.CSharp:
|
||||
model = CreateCSharpAlphaModel();
|
||||
return true;
|
||||
case Language.Python:
|
||||
Algorithm.SetPandasConverter();
|
||||
model = CreatePythonAlphaModel();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using NUnit.Framework;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using static System.FormattableString;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
[TestFixture]
|
||||
public class ConstantAlphaModelTests : CommonAlphaModelTests
|
||||
{
|
||||
private InsightType _type = InsightType.Price;
|
||||
private InsightDirection _direction = InsightDirection.Up;
|
||||
private TimeSpan _period = Time.OneDay;
|
||||
private double? _magnitude = 0.025;
|
||||
private double? _confidence = null;
|
||||
|
||||
protected override IAlphaModel CreateCSharpAlphaModel() => new ConstantAlphaModel(_type, _direction, _period, _magnitude, _confidence);
|
||||
|
||||
protected override IAlphaModel CreatePythonAlphaModel()
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
dynamic model = Py.Import("ConstantAlphaModel").GetAttr("ConstantAlphaModel");
|
||||
var instance = model(_type, _direction, _period, _magnitude, _confidence);
|
||||
return new AlphaModelPythonWrapper(instance);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(Language.CSharp)]
|
||||
[TestCase(Language.Python)]
|
||||
public void ConstructorWithWeightOnlySetsWeightCorrectly(Language language)
|
||||
{
|
||||
IAlphaModel alpha;
|
||||
if (language == Language.CSharp)
|
||||
{
|
||||
alpha = new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromDays(1), weight: 0.1);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
var testModule = PyModule.FromString("test_module",
|
||||
@"
|
||||
from AlgorithmImports import *
|
||||
|
||||
def test_constructor():
|
||||
model = ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(1), weight=0.1)
|
||||
return model
|
||||
");
|
||||
|
||||
alpha = testModule.GetAttr("test_constructor").Invoke().As<ConstantAlphaModel>();
|
||||
}
|
||||
}
|
||||
|
||||
var magnitude = GetPrivateField(alpha, "_magnitude");
|
||||
var confidence = GetPrivateField(alpha, "_confidence");
|
||||
var weight = GetPrivateField(alpha, "_weight");
|
||||
|
||||
Assert.IsNull(magnitude);
|
||||
Assert.IsNull(confidence);
|
||||
Assert.AreEqual(0.1, weight);
|
||||
}
|
||||
|
||||
private static object GetPrivateField(object obj, string fieldName)
|
||||
{
|
||||
var field = obj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
return field?.GetValue(obj);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Insight> ExpectedInsights()
|
||||
{
|
||||
return Enumerable.Range(0, 360).Select(x => new Insight(Symbols.SPY, _period, _type, _direction, _magnitude, _confidence));
|
||||
}
|
||||
|
||||
protected override string GetExpectedModelName(IAlphaModel model)
|
||||
{
|
||||
return Invariant($"{nameof(ConstantAlphaModel)}({_type},{_direction},{_period},{_magnitude})");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using NUnit.Framework;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Algorithm.Framework.Selection;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Tests.Common.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
[TestFixture]
|
||||
public class EmaCrossAlphaModelTests : CommonAlphaModelTests
|
||||
{
|
||||
protected override IAlphaModel CreateCSharpAlphaModel() => new EmaCrossAlphaModel();
|
||||
|
||||
protected override IAlphaModel CreatePythonAlphaModel()
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
dynamic model = Py.Import("EmaCrossAlphaModel").GetAttr("EmaCrossAlphaModel");
|
||||
var instance = model();
|
||||
return new AlphaModelPythonWrapper(instance);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<Insight> ExpectedInsights()
|
||||
{
|
||||
var period = TimeSpan.FromDays(12);
|
||||
|
||||
return new[]
|
||||
{
|
||||
Insight.Price(Symbols.SPY, period, InsightDirection.Down),
|
||||
Insight.Price(Symbols.SPY, period, InsightDirection.Up)
|
||||
};
|
||||
}
|
||||
|
||||
protected override string GetExpectedModelName(IAlphaModel model)
|
||||
{
|
||||
return $"{nameof(EmaCrossAlphaModel)}(12,26,Daily)";
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WarmsUpProperly()
|
||||
{
|
||||
SetUpHistoryProvider();
|
||||
|
||||
Algorithm.SetStartDate(2013, 10, 08);
|
||||
Algorithm.SetUniverseSelection(new ManualUniverseSelectionModel());
|
||||
|
||||
// Create a EmaCrossAlphaModel for the test
|
||||
var model = new TestEmaCrossAlphaModel();
|
||||
|
||||
// Set the alpha model
|
||||
Algorithm.SetAlpha(model);
|
||||
Algorithm.SetUniverseSelection(new ManualUniverseSelectionModel());
|
||||
|
||||
var changes = SecurityChangesTests.CreateNonInternal(AddedSecurities, RemovedSecurities);
|
||||
Algorithm.OnFrameworkSecuritiesChanged(changes);
|
||||
|
||||
// Get the dictionary of macd indicators
|
||||
var symbolData = model.GetSymbolData();
|
||||
|
||||
// Check the symbolData dictionary is not empty
|
||||
Assert.NotZero(symbolData.Count);
|
||||
|
||||
// Check all EmaCross indicators from the alpha are ready and have at least
|
||||
// one datapoint
|
||||
foreach (var item in symbolData)
|
||||
{
|
||||
var fast = item.Value.Fast;
|
||||
var slow = item.Value.Slow;
|
||||
|
||||
Assert.IsTrue(fast.IsReady);
|
||||
Assert.NotZero(fast.Samples);
|
||||
|
||||
Assert.IsTrue(slow.IsReady);
|
||||
Assert.NotZero(slow.Samples);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PythonVersionWarmsUpProperly()
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
SetUpHistoryProvider();
|
||||
Algorithm.SetStartDate(2013, 10, 08);
|
||||
Algorithm.SetUniverseSelection(new ManualUniverseSelectionModel());
|
||||
|
||||
// Create and set alpha model
|
||||
dynamic model = Py.Import("EmaCrossAlphaModel").GetAttr("EmaCrossAlphaModel");
|
||||
var instance = model();
|
||||
Algorithm.SetAlpha(instance);
|
||||
|
||||
var changes = SecurityChangesTests.CreateNonInternal(AddedSecurities, RemovedSecurities);
|
||||
Algorithm.OnFrameworkSecuritiesChanged(changes);
|
||||
|
||||
// Get the dictionary of ema cross indicators
|
||||
var symbolData = instance.symbol_data_by_symbol;
|
||||
|
||||
// Check the dictionary is not empty
|
||||
Assert.NotZero(symbolData.Length());
|
||||
|
||||
// Check all Ema Cross indicators from the alpha are ready and have at least
|
||||
// one datapoint
|
||||
foreach (var item in symbolData)
|
||||
{
|
||||
var fast = symbolData[item].fast;
|
||||
var slow = symbolData[item].slow;
|
||||
|
||||
Assert.IsTrue(fast.IsReady.IsTrue());
|
||||
Assert.NotZero(((PyObject)fast.Samples).GetAndDispose<int>());
|
||||
|
||||
Assert.IsTrue(slow.IsReady.IsTrue());
|
||||
Assert.NotZero(((PyObject)slow.Samples).GetAndDispose<int>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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 System.Linq;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
[TestFixture]
|
||||
public class InsightCollectionTests
|
||||
{
|
||||
private static readonly DateTime _referenceTime = new DateTime(2019, 1, 1);
|
||||
|
||||
[Test]
|
||||
public void InsightCollectionShouldBeAbleToBeConvertedToListWithoutStackOverflow()
|
||||
{
|
||||
var insightCollection = new InsightCollection
|
||||
{
|
||||
new Insight(Symbols.AAPL, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up)
|
||||
{
|
||||
CloseTimeUtc = new DateTime(2019, 1, 1),
|
||||
},
|
||||
new Insight(Symbols.AAPL, new TimeSpan(1, 0, 0, 0), InsightType.Volatility, InsightDirection.Up)
|
||||
{
|
||||
CloseTimeUtc = new DateTime(2019, 1, 2),
|
||||
}
|
||||
};
|
||||
|
||||
Assert.DoesNotThrow(() => insightCollection.OrderBy(x => x.CloseTimeUtc).ToList());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasActiveInsights()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
|
||||
Assert.IsFalse(collection.HasActiveInsights(Symbols.AAPL, DateTime.MinValue));
|
||||
|
||||
collection.AddRange(GetTestInsight());
|
||||
|
||||
Assert.IsFalse(collection.HasActiveInsights(Symbols.AAPL, DateTime.MaxValue));
|
||||
|
||||
Assert.IsTrue(collection.HasActiveInsights(Symbols.AAPL, _referenceTime));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetNextExpiryTime()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
|
||||
Assert.AreEqual(null, collection.GetNextExpiryTime());
|
||||
|
||||
collection.AddRange(GetTestInsight());
|
||||
|
||||
Assert.AreEqual(_referenceTime, collection.GetNextExpiryTime());
|
||||
|
||||
var nextDay = _referenceTime.AddDays(1);
|
||||
Assert.AreEqual(1, collection.RemoveExpiredInsights(nextDay).Count);
|
||||
Assert.AreEqual(nextDay, collection.GetNextExpiryTime());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetValue()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
|
||||
Assert.IsFalse(collection.TryGetValue(Symbols.AAPL, out var _));
|
||||
|
||||
collection.AddRange(GetTestInsight());
|
||||
Assert.IsTrue(collection.TryGetValue(Symbols.AAPL, out var insights));
|
||||
|
||||
Assert.AreEqual(2, insights.Count);
|
||||
Assert.AreEqual(2, insights.Count(insight => insight.Symbol == Symbols.AAPL));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void KeyNotFoundException()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
Assert.Throws<KeyNotFoundException>(() =>
|
||||
{
|
||||
var insight = collection[Symbols.AAPL];
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Contains()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
var insights = GetTestInsight();
|
||||
collection.AddRange(insights);
|
||||
|
||||
foreach (var insight in insights)
|
||||
{
|
||||
Assert.IsTrue(collection.Contains(insight));
|
||||
Assert.IsTrue(collection.ContainsKey(insight.Symbol));
|
||||
}
|
||||
Assert.IsFalse(collection.ContainsKey(Symbols.BTCEUR));
|
||||
|
||||
var anotherInsight = new Insight(Symbols.BTCEUR, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up);
|
||||
Assert.IsFalse(collection.Contains(anotherInsight));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Addition()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
var insight = new Insight(Symbols.AAPL, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up) { CloseTimeUtc = _referenceTime };
|
||||
collection.Add(insight);
|
||||
collection.Add(new Insight(Symbols.SPY, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up) { CloseTimeUtc = _referenceTime });
|
||||
collection.Add(new Insight(Symbols.IBM, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Down) { CloseTimeUtc = _referenceTime.AddDays(-1) });
|
||||
|
||||
var beforeExpiration = insight.CloseTimeUtc.AddDays(-1);
|
||||
|
||||
Assert.AreEqual(3, collection.Count);
|
||||
Assert.IsTrue(collection.TryGetValue(Symbols.AAPL, out var insightInCollection));
|
||||
Assert.IsTrue(collection.HasActiveInsights(Symbols.AAPL, beforeExpiration));
|
||||
Assert.AreEqual(insight, insightInCollection.Single());
|
||||
Assert.AreEqual(insight, collection[Symbols.AAPL].Single());
|
||||
Assert.AreEqual(3, collection.Count);
|
||||
Assert.AreEqual(3, collection.GetActiveInsights(beforeExpiration).Count);
|
||||
Assert.AreEqual(3, collection.GetInsights().Count);
|
||||
Assert.AreEqual(insight, collection.GetInsights(x => insight == x).Single());
|
||||
Assert.AreEqual(0, collection.GetActiveInsights(_referenceTime.AddYears(1)).Count);
|
||||
Assert.AreEqual(3, collection.TotalCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetInsights()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
var insights = GetTestInsight();
|
||||
collection.AddRange(insights);
|
||||
|
||||
Assert.AreEqual(5, collection.Count);
|
||||
|
||||
collection.RemoveInsights(x => x == insights[0]);
|
||||
Assert.AreEqual(4, collection.GetInsights().Count);
|
||||
Assert.AreEqual(4, collection.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Removal()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
var insights = GetTestInsight();
|
||||
collection.AddRange(insights);
|
||||
|
||||
var insightCount = collection.Count;
|
||||
foreach (var insight in insights)
|
||||
{
|
||||
Assert.IsTrue(collection.Remove(insight));
|
||||
Assert.AreEqual(--insightCount, collection.Count);
|
||||
}
|
||||
|
||||
// readd the first insight
|
||||
var firstInsight = insights[0];
|
||||
collection.Add(firstInsight);
|
||||
Assert.AreEqual(1, collection.Count);
|
||||
|
||||
// we only remove 'firstInsight' from the global collection
|
||||
collection.RemoveInsights(x => x == firstInsight);
|
||||
Assert.AreEqual(4, collection.GetInsights().Count);
|
||||
Assert.AreEqual(0, collection.Count);
|
||||
Assert.AreEqual(6, collection.TotalCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExpiredRemoval()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
var insights = GetTestInsight();
|
||||
collection.AddRange(insights);
|
||||
|
||||
Assert.AreEqual(5, collection.Count);
|
||||
Assert.AreEqual(0, collection.RemoveExpiredInsights(_referenceTime.AddDays(-1)).Count);
|
||||
|
||||
// expire 1 insight
|
||||
Assert.AreEqual(insights[0], collection.RemoveExpiredInsights(_referenceTime.AddDays(1)).Single());
|
||||
|
||||
// expire 2 insights
|
||||
Assert.AreEqual(2, collection.RemoveExpiredInsights(_referenceTime.AddDays(2)).Count);
|
||||
Assert.AreEqual(2, collection.Count);
|
||||
Assert.AreEqual(5, collection.TotalCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IndexAccess()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
collection.AddRange(GetTestInsight());
|
||||
|
||||
collection[Symbols.AAPL] = null;
|
||||
Assert.AreEqual(3, collection.Count);
|
||||
|
||||
var insight = new Insight(Symbols.AAPL, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up) { CloseTimeUtc = new DateTime(2019, 1, 1) };
|
||||
var insight2 = new Insight(Symbols.AAPL, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up) { CloseTimeUtc = new DateTime(2019, 1, 2) };
|
||||
collection[Symbols.AAPL] = new() { insight, insight2 };
|
||||
Assert.AreEqual(5, collection.Count);
|
||||
|
||||
collection[Symbols.AAPL] = null;
|
||||
Assert.AreEqual(3, collection.Count);
|
||||
|
||||
Assert.AreEqual(7, collection.TotalCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddRange()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
var insights = GetTestInsight();
|
||||
collection.AddRange(insights);
|
||||
|
||||
Assert.AreEqual(5, collection.Count);
|
||||
|
||||
foreach (var insight in insights)
|
||||
{
|
||||
Assert.IsTrue(collection.Contains(insight));
|
||||
Assert.IsTrue(collection.ContainsKey(insight.Symbol));
|
||||
}
|
||||
Assert.AreEqual(5, collection.TotalCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearSymbols()
|
||||
{
|
||||
var collection = new InsightCollection();
|
||||
collection.AddRange(GetTestInsight());
|
||||
|
||||
collection.Clear(Array.Empty<Symbol>());
|
||||
Assert.AreEqual(5, collection.Count);
|
||||
|
||||
collection.Clear(new[] { Symbols.AAPL });
|
||||
Assert.AreEqual(3, collection.Count);
|
||||
Assert.IsTrue(collection.ContainsKey(Symbols.SPY));
|
||||
Assert.IsTrue(collection.ContainsKey(Symbols.IBM));
|
||||
Assert.IsFalse(collection.ContainsKey(Symbols.AAPL));
|
||||
Assert.AreEqual(5, collection.TotalCount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static List<Insight> GetTestInsight()
|
||||
{
|
||||
var insight = new Insight(Symbols.AAPL, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up) { CloseTimeUtc = _referenceTime };
|
||||
var insight2 = new Insight(Symbols.AAPL, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up) { CloseTimeUtc = _referenceTime.AddDays(1) };
|
||||
var insight3 = new Insight(Symbols.SPY, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up) { CloseTimeUtc = _referenceTime.AddDays(1) };
|
||||
|
||||
var insight4 = new Insight(Symbols.SPY, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Down) { CloseTimeUtc = _referenceTime.AddMonths(1) };
|
||||
var insight5 = new Insight(Symbols.IBM, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Down) { CloseTimeUtc = _referenceTime.AddMonths(1) };
|
||||
|
||||
return new List<Insight> { insight, insight2, insight3, insight4, insight5 };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Tests.Engine.DataFeeds;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
using QuantConnect.Algorithm.Framework.Alphas.Analysis;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
[TestFixture]
|
||||
public class InsightManagerTests
|
||||
{
|
||||
private static readonly DateTime _utcNow = new (2019, 1, 1);
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void ExpireSameTime(bool useCancelApi)
|
||||
{
|
||||
var algorithm = new AlgorithmStub();
|
||||
algorithm.SetDateTime(_utcNow);
|
||||
var insightManager = new InsightManager(algorithm);
|
||||
insightManager.AddRange(GetInsights());
|
||||
|
||||
Assert.IsTrue(insightManager.All(insight => insight.IsActive(_utcNow)));
|
||||
|
||||
if (useCancelApi)
|
||||
{
|
||||
insightManager.Cancel(new[] { Symbols.IBM, Symbols.SPY });
|
||||
}
|
||||
else
|
||||
{
|
||||
insightManager.Expire(new[] { Symbols.IBM, Symbols.SPY });
|
||||
}
|
||||
|
||||
Assert.IsTrue(insightManager[Symbols.IBM].All(insight => insight.IsExpired(algorithm.UtcTime) && insight.Period == TimeSpan.FromSeconds(-1)));
|
||||
Assert.IsTrue(insightManager[Symbols.SPY].All(insight => insight.IsExpired(algorithm.UtcTime) && insight.Period == TimeSpan.FromSeconds(-1)));
|
||||
Assert.IsTrue(insightManager[Symbols.AAPL].All(insight => insight.IsActive(algorithm.UtcTime)));
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void ExpireBySymbol(bool useCancelApi)
|
||||
{
|
||||
var algorithm = new AlgorithmStub();
|
||||
algorithm.SetDateTime(_utcNow);
|
||||
var insightManager = new InsightManager(algorithm);
|
||||
insightManager.AddRange(GetInsights());
|
||||
|
||||
Assert.IsTrue(insightManager.All(insight => insight.IsActive(_utcNow)));
|
||||
|
||||
algorithm.SetDateTime(algorithm.UtcTime.AddMinutes(1));
|
||||
if (useCancelApi)
|
||||
{
|
||||
insightManager.Cancel(new[] { Symbols.IBM, Symbols.SPY });
|
||||
}
|
||||
else
|
||||
{
|
||||
insightManager.Expire(new[] { Symbols.IBM, Symbols.SPY });
|
||||
}
|
||||
|
||||
var expectedPeriod = Time.OneMinute.Subtract(Time.OneSecond);
|
||||
Assert.IsTrue(insightManager[Symbols.IBM].All(insight => insight.IsExpired(algorithm.UtcTime) && insight.Period == expectedPeriod));
|
||||
Assert.IsTrue(insightManager[Symbols.SPY].All(insight => insight.IsExpired(algorithm.UtcTime) && insight.Period == expectedPeriod));
|
||||
Assert.IsTrue(insightManager[Symbols.AAPL].All(insight => insight.IsActive(algorithm.UtcTime)));
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void ExpireByInsight(bool useCancelApi)
|
||||
{
|
||||
var algorithm = new AlgorithmStub();
|
||||
algorithm.SetDateTime(_utcNow);
|
||||
var insights = GetInsights();
|
||||
var insightManager = new InsightManager(algorithm);
|
||||
insightManager.AddRange(insights);
|
||||
|
||||
Assert.IsTrue(insightManager.All(insight => insight.IsActive(_utcNow)));
|
||||
|
||||
algorithm.SetDateTime(algorithm.UtcTime.AddMinutes(1));
|
||||
if (useCancelApi)
|
||||
{
|
||||
insightManager.Cancel(new[] { insights[2], insights[3] });
|
||||
}
|
||||
else
|
||||
{
|
||||
insightManager.Expire(new[] { insights[2], insights[3] });
|
||||
}
|
||||
|
||||
var expectedPeriod = Time.OneMinute.Subtract(Time.OneSecond);
|
||||
Assert.IsTrue(insightManager[Symbols.IBM].All(insight => insight.IsExpired(algorithm.UtcTime) && insight.Period == expectedPeriod));
|
||||
Assert.AreEqual(1, insightManager[Symbols.SPY].Count(insight => insight.IsExpired(algorithm.UtcTime) && insight.Period == expectedPeriod));
|
||||
Assert.AreEqual(1, insightManager[Symbols.SPY].Count(insight => insight.IsActive(algorithm.UtcTime)));
|
||||
Assert.IsTrue(insightManager[Symbols.AAPL].All(insight => insight.IsActive(algorithm.UtcTime)));
|
||||
}
|
||||
|
||||
private static Insight[] GetInsights()
|
||||
{
|
||||
return new[] {
|
||||
new Insight(Symbols.AAPL, new TimeSpan(1, 0, 0, 0), InsightType.Price, InsightDirection.Up)
|
||||
{
|
||||
GeneratedTimeUtc = _utcNow,
|
||||
CloseTimeUtc = _utcNow.AddDays(1),
|
||||
},
|
||||
new Insight(Symbols.SPY, new TimeSpan(2, 0, 0, 0), InsightType.Volatility, InsightDirection.Up)
|
||||
{
|
||||
GeneratedTimeUtc = _utcNow,
|
||||
CloseTimeUtc = _utcNow.AddDays(2),
|
||||
},
|
||||
new Insight(Symbols.SPY, new TimeSpan(3, 0, 0, 0), InsightType.Volatility, InsightDirection.Up)
|
||||
{
|
||||
GeneratedTimeUtc = _utcNow,
|
||||
CloseTimeUtc = _utcNow.AddDays(3),
|
||||
},
|
||||
new Insight(Symbols.IBM, new TimeSpan(4, 0, 0, 0), InsightType.Volatility, InsightDirection.Up)
|
||||
{
|
||||
GeneratedTimeUtc = _utcNow,
|
||||
CloseTimeUtc = _utcNow.AddDays(4),
|
||||
} };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using NUnit.Framework;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Algorithm.Framework.Selection;
|
||||
using QuantConnect.Tests.Common.Data.UniverseSelection;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
[TestFixture]
|
||||
public class MacdAlphaModelTests : CommonAlphaModelTests
|
||||
{
|
||||
protected override IAlphaModel CreateCSharpAlphaModel() => new MacdAlphaModel();
|
||||
|
||||
protected override IAlphaModel CreatePythonAlphaModel()
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
dynamic model = Py.Import("MacdAlphaModel").GetAttr("MacdAlphaModel");
|
||||
var instance = model();
|
||||
return new AlphaModelPythonWrapper(instance);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<Insight> ExpectedInsights()
|
||||
{
|
||||
var period = TimeSpan.FromDays(12);
|
||||
return new[]
|
||||
{
|
||||
Insight.Price(Symbols.SPY, period, InsightDirection.Up),
|
||||
Insight.Price(Symbols.SPY, period, InsightDirection.Down),
|
||||
Insight.Price(Symbols.SPY, period, InsightDirection.Up)
|
||||
};
|
||||
}
|
||||
|
||||
protected override string GetExpectedModelName(IAlphaModel model)
|
||||
{
|
||||
return $"{nameof(MacdAlphaModel)}(12,26,9,Exponential,Daily)";
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MacdAlphaModelWarmsUpProperly()
|
||||
{
|
||||
SetUpHistoryProvider();
|
||||
Algorithm.SetStartDate(2013, 10, 08);
|
||||
|
||||
// Create a MacdAlphaModel for the test
|
||||
var model = new TestMacdAlphaModel();
|
||||
|
||||
// Set the alpha model
|
||||
Algorithm.SetAlpha(model);
|
||||
Algorithm.SetUniverseSelection(new ManualUniverseSelectionModel());
|
||||
|
||||
var changes = SecurityChangesTests.CreateNonInternal(AddedSecurities, RemovedSecurities);
|
||||
Algorithm.OnFrameworkSecuritiesChanged(changes);
|
||||
|
||||
// Get the dictionary of macd indicators
|
||||
var symbolData = model.GetSymbolData();
|
||||
|
||||
// Check the symbolData dictionary is not empty
|
||||
Assert.NotZero(symbolData.Count);
|
||||
|
||||
// Check all MACD indicators from the alpha are ready and have at least
|
||||
// one datapoint
|
||||
foreach (var item in symbolData)
|
||||
{
|
||||
var macd = item.Value.MACD;
|
||||
|
||||
Assert.IsTrue(macd.IsReady);
|
||||
Assert.NotZero(macd.Samples);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PythonMacdAlphaModelWarmsUpProperly()
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
SetUpHistoryProvider();
|
||||
Algorithm.SetStartDate(2013, 10, 08);
|
||||
Algorithm.SetUniverseSelection(new ManualUniverseSelectionModel());
|
||||
|
||||
// Create and set alpha model
|
||||
dynamic model = Py.Import("MacdAlphaModel").GetAttr("MacdAlphaModel");
|
||||
var instance = model();
|
||||
Algorithm.SetAlpha(instance);
|
||||
|
||||
var changes = SecurityChangesTests.CreateNonInternal(AddedSecurities, RemovedSecurities);
|
||||
Algorithm.OnFrameworkSecuritiesChanged(changes);
|
||||
|
||||
// Get the dictionary of macd indicators
|
||||
var symbolData = instance.symbolData;
|
||||
|
||||
// Check the dictionary is not empty
|
||||
Assert.NotZero(symbolData.Length());
|
||||
|
||||
// Check all MACD indicators from the alpha are ready and have at least
|
||||
// one datapoint
|
||||
foreach (var item in symbolData)
|
||||
{
|
||||
var macd = symbolData[item].MACD;
|
||||
|
||||
Assert.IsTrue(macd.IsReady.IsTrue());
|
||||
Assert.NotZero(((PyObject)macd.Samples).GetAndDispose<int>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using NUnit.Framework;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
[TestFixture]
|
||||
public class RsiAlphaModelTests : CommonAlphaModelTests
|
||||
{
|
||||
protected override IAlphaModel CreateCSharpAlphaModel() => new RsiAlphaModel();
|
||||
|
||||
protected override IAlphaModel CreatePythonAlphaModel()
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
dynamic model = Py.Import("RsiAlphaModel").GetAttr("RsiAlphaModel");
|
||||
var instance = model();
|
||||
return new AlphaModelPythonWrapper(instance);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<Insight> ExpectedInsights()
|
||||
{
|
||||
var period = TimeSpan.FromDays(14);
|
||||
foreach (var direction in new[] { InsightDirection.Up, InsightDirection.Down })
|
||||
{
|
||||
yield return Insight.Price(Symbols.SPY, period, direction);
|
||||
}
|
||||
}
|
||||
|
||||
protected override string GetExpectedModelName(IAlphaModel model)
|
||||
{
|
||||
return $"{nameof(RsiAlphaModel)}(14,Daily)";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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 Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Algorithm.Framework.Alphas;
|
||||
using QuantConnect.Algorithm.Framework.Alphas.Serialization;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas.Serialization
|
||||
{
|
||||
[TestFixture, Parallelizable(ParallelScope.All)]
|
||||
public class InsightJsonConverterTests
|
||||
{
|
||||
private JsonSerializerSettings _serializerSettings = new()
|
||||
{
|
||||
ContractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy
|
||||
{
|
||||
ProcessDictionaryKeys = false,
|
||||
OverrideSpecifiedNames = true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void DeserializesInsightWithoutScore()
|
||||
{
|
||||
var jObject = JObject.Parse(jsonNoScoreBackwardsCompatible);
|
||||
var result = JsonConvert.DeserializeObject<Insight>(jsonNoScoreBackwardsCompatible);
|
||||
Assert.AreEqual(jObject["id"].Value<string>(), result.Id.ToStringInvariant("N"));
|
||||
Assert.AreEqual(jObject["source-model"].Value<string>(), result.SourceModel);
|
||||
Assert.AreEqual(jObject["group-id"]?.Value<string>(), result.GroupId?.ToStringInvariant("N"));
|
||||
Assert.AreEqual(jObject["created-time"].Value<double>(), Time.DateTimeToUnixTimeStamp(result.GeneratedTimeUtc), 5e-4);
|
||||
Assert.AreEqual(jObject["close-time"].Value<double>(), Time.DateTimeToUnixTimeStamp(result.CloseTimeUtc), 5e-4);
|
||||
Assert.AreEqual(jObject["symbol"].Value<string>(), result.Symbol.ID.ToString());
|
||||
Assert.AreEqual(jObject["ticker"].Value<string>(), result.Symbol.Value);
|
||||
Assert.AreEqual(jObject["type"].Value<string>(), result.Type.ToLower());
|
||||
Assert.AreEqual(jObject["reference"].Value<decimal>(), result.ReferenceValue);
|
||||
Assert.AreEqual(jObject["direction"].Value<string>(), result.Direction.ToLower());
|
||||
Assert.AreEqual(jObject["period"].Value<double>(), result.Period.TotalSeconds);
|
||||
Assert.AreEqual(jObject["magnitude"].Value<double>(), result.Magnitude);
|
||||
Assert.AreEqual(null, result.Confidence);
|
||||
|
||||
// default values for scores
|
||||
Assert.AreEqual(false, result.Score.IsFinalScore);
|
||||
Assert.AreEqual(0, result.ReferenceValueFinal);
|
||||
Assert.AreEqual(0, result.Score.Magnitude);
|
||||
Assert.AreEqual(0, result.Score.Direction);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializesInsightWithScore()
|
||||
{
|
||||
var jObject = JObject.Parse(jsonWithScoreBackwardsCompatible);
|
||||
var result = JsonConvert.DeserializeObject<Insight>(jsonWithScoreBackwardsCompatible);
|
||||
Assert.AreEqual(jObject["id"].Value<string>(), result.Id.ToStringInvariant("N"));
|
||||
Assert.AreEqual(jObject["source-model"].Value<string>(), result.SourceModel);
|
||||
Assert.AreEqual(jObject["group-id"]?.Value<string>(), result.GroupId?.ToStringInvariant("N"));
|
||||
Assert.AreEqual(jObject["created-time"].Value<double>(), Time.DateTimeToUnixTimeStamp(result.GeneratedTimeUtc), 5e-4);
|
||||
Assert.AreEqual(jObject["close-time"].Value<double>(), Time.DateTimeToUnixTimeStamp(result.CloseTimeUtc), 5e-4);
|
||||
Assert.AreEqual(jObject["symbol"].Value<string>(), result.Symbol.ID.ToString());
|
||||
Assert.AreEqual(jObject["ticker"].Value<string>(), result.Symbol.Value);
|
||||
Assert.AreEqual(jObject["type"].Value<string>(), result.Type.ToLower());
|
||||
Assert.AreEqual(jObject["reference"].Value<decimal>(), result.ReferenceValue);
|
||||
Assert.AreEqual(jObject["direction"].Value<string>(), result.Direction.ToLower());
|
||||
Assert.AreEqual(jObject["period"].Value<double>(), result.Period.TotalSeconds);
|
||||
Assert.AreEqual(jObject["magnitude"].Value<double>(), result.Magnitude);
|
||||
Assert.AreEqual(null, result.Confidence);
|
||||
Assert.AreEqual(true, result.Score.IsFinalScore);
|
||||
Assert.AreEqual(jObject["score-magnitude"].Value<double>(), result.Score.Magnitude);
|
||||
Assert.AreEqual(jObject["score-direction"].Value<double>(), result.Score.Direction);
|
||||
Assert.AreEqual(jObject["reference-final"].Value<decimal>(), result.ReferenceValueFinal);
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void SerializesInsightWithoutScore(bool backwardsCompatible)
|
||||
{
|
||||
var serializedInsight = JsonConvert.DeserializeObject<SerializedInsight>(backwardsCompatible ? jsonNoScoreBackwardsCompatible : jsonNoScore2);
|
||||
var insight = Insight.FromSerializedInsight(serializedInsight);
|
||||
var result = JsonConvert.SerializeObject(insight, Formatting.None, _serializerSettings);
|
||||
Assert.AreEqual(jsonNoScore2, result);
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void SerializesInsightWithScore(bool backwardsCompatible)
|
||||
{
|
||||
var serializedInsight = JsonConvert.DeserializeObject<SerializedInsight>(backwardsCompatible ? jsonWithScoreBackwardsCompatible : jsonWithScore);
|
||||
var insight = Insight.FromSerializedInsight(serializedInsight);
|
||||
var result = JsonConvert.SerializeObject(insight, Formatting.None, _serializerSettings);
|
||||
Assert.AreEqual(jsonWithScore, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializesOldInsightWithMissingCreatedTime()
|
||||
{
|
||||
var serializedInsight = JsonConvert.DeserializeObject<SerializedInsight>(jsonWithMissingCreatedTimeBackwardsCompatible);
|
||||
var insight = Insight.FromSerializedInsight(serializedInsight);
|
||||
var result = JsonConvert.SerializeObject(insight, Formatting.None, _serializerSettings);
|
||||
|
||||
Assert.AreEqual(serializedInsight.CreatedTime, serializedInsight.GeneratedTime);
|
||||
Assert.AreEqual(jsonWithExpectedOutputFromMissingCreatedTimeValue, result);
|
||||
}
|
||||
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void SerializesInsightWithTag(bool backwardsCompatible)
|
||||
{
|
||||
var serializedInsight = JsonConvert.DeserializeObject<SerializedInsight>(backwardsCompatible ? jsonWithTagBackwardsCompatible : jsonWithTag);
|
||||
var insight = Insight.FromSerializedInsight(serializedInsight);
|
||||
var result = JsonConvert.SerializeObject(insight, Formatting.None, _serializerSettings);
|
||||
Assert.AreEqual(jsonWithTag, result);
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void SerializesInsightWithoutTag(bool backwardsCompatible)
|
||||
{
|
||||
var serializedInsight = JsonConvert.DeserializeObject<SerializedInsight>(backwardsCompatible ? jsonWithoutTagBackwardsCompatible : jsonWithoutTag);
|
||||
var insight = Insight.FromSerializedInsight(serializedInsight);
|
||||
var result = JsonConvert.SerializeObject(insight, Formatting.None, _serializerSettings);
|
||||
Assert.AreEqual(jsonWithoutTag, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializesInsightWithTag()
|
||||
{
|
||||
var jObject = JObject.Parse(jsonWithTagBackwardsCompatible);
|
||||
var result = JsonConvert.DeserializeObject<Insight>(jsonWithTagBackwardsCompatible);
|
||||
Assert.AreEqual(jObject["tag"].Value<string>(), result.Tag);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializesInsightWithoutTag()
|
||||
{
|
||||
var result = JsonConvert.DeserializeObject<Insight>(jsonWithoutTagBackwardsCompatible);
|
||||
Assert.IsNull(result.Tag);
|
||||
}
|
||||
|
||||
private string jsonNoScore2 = @"{""id"":""e02be50f56a8496b9ba995d19a904ada"",""groupId"":null,""sourceModel"":""mySourceModel-1"",""generatedTime"":1520711961.00055,
|
||||
""createdTime"":1520711961.00055,""closeTime"":1520711961.00055,""symbol"":""BTCUSD XJ"",""ticker"":""BTCUSD"",""type"":""price"",""reference"":9143.53,""referenceValueFinal"":0.0,
|
||||
""direction"":""up"",""period"":5.0,""magnitude"":""0.025"",""confidence"":null,""weight"":null,""scoreIsFinal"":false,""scoreMagnitude"":""0"",""scoreDirection"":""0"",
|
||||
""estimatedValue"":""0"",""tag"":null}".ReplaceLineEndings(string.Empty);
|
||||
|
||||
private const string jsonNoScoreBackwardsCompatible =
|
||||
"{" +
|
||||
"\"id\":\"e02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"group-id\":null," +
|
||||
"\"source-model\":\"mySourceModel-1\"," +
|
||||
"\"generated-time\":1520711961.00055," +
|
||||
"\"created-time\":1520711961.00055," +
|
||||
"\"close-time\":1520711961.00055," +
|
||||
"\"symbol\":\"BTCUSD XJ\"," +
|
||||
"\"ticker\":\"BTCUSD\"," +
|
||||
"\"type\":\"price\"," +
|
||||
"\"reference\":9143.53," +
|
||||
"\"reference-final\":0.0," +
|
||||
"\"direction\":\"up\"," +
|
||||
"\"period\":5.0," +
|
||||
"\"magnitude\":\"0.025\"," +
|
||||
"\"confidence\":null," +
|
||||
"\"weight\":null," +
|
||||
"\"score-final\":false," +
|
||||
"\"score-magnitude\":\"0\"," +
|
||||
"\"score-direction\":\"0\"," +
|
||||
"\"estimated-value\":\"0\"," +
|
||||
"\"tag\":null}";
|
||||
|
||||
private string jsonWithScore = @"{""id"":""e02be50f56a8496b9ba995d19a904ada"",""groupId"":""a02be50f56a8496b9ba995d19a904ada"",""sourceModel"":""mySourceModel-1"",
|
||||
""generatedTime"":1520711961.00055,""createdTime"":1520711961.00055,""closeTime"":1520711961.00055,""symbol"":""BTCUSD XJ"",""ticker"":""BTCUSD"",""type"":""price"",
|
||||
""reference"":9143.53,""referenceValueFinal"":9243.53,""direction"":""up"",""period"":5.0,""magnitude"":""0.025"",""confidence"":null,""weight"":null,
|
||||
""scoreIsFinal"":true,""scoreMagnitude"":""1"",""scoreDirection"":""1"",""estimatedValue"":""1113.2484"",""tag"":null}".ReplaceLineEndings(string.Empty);
|
||||
private const string jsonWithScoreBackwardsCompatible =
|
||||
"{" +
|
||||
"\"id\":\"e02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"group-id\":\"a02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"source-model\":\"mySourceModel-1\"," +
|
||||
"\"generated-time\":1520711961.00055," +
|
||||
"\"created-time\":1520711961.00055," +
|
||||
"\"close-time\":1520711961.00055," +
|
||||
"\"symbol\":\"BTCUSD XJ\"," +
|
||||
"\"ticker\":\"BTCUSD\"," +
|
||||
"\"type\":\"price\"," +
|
||||
"\"reference\":9143.53," +
|
||||
"\"reference-final\":9243.53," +
|
||||
"\"direction\":\"up\"," +
|
||||
"\"period\":5.0," +
|
||||
"\"magnitude\":\"0.025\"," +
|
||||
"\"confidence\":null," +
|
||||
"\"weight\":null," +
|
||||
"\"score-final\":true," +
|
||||
"\"score-magnitude\":\"1\"," +
|
||||
"\"score-direction\":\"1\"," +
|
||||
"\"estimated-value\":\"1113.2484\"," +
|
||||
"\"tag\":null}";
|
||||
|
||||
private const string jsonWithMissingCreatedTimeBackwardsCompatible =
|
||||
"{" +
|
||||
"\"id\":\"e02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"group-id\":\"a02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"source-model\":\"mySourceModel-1\"," +
|
||||
"\"generated-time\":1520711961.00055," +
|
||||
"\"close-time\":1520711961.00055," +
|
||||
"\"symbol\":\"BTCUSD XJ\"," +
|
||||
"\"ticker\":\"BTCUSD\"," +
|
||||
"\"type\":\"price\"," +
|
||||
"\"reference\":9143.53," +
|
||||
"\"reference-final\":9243.53," +
|
||||
"\"direction\":\"up\"," +
|
||||
"\"period\":5.0," +
|
||||
"\"magnitude\":0.025," +
|
||||
"\"confidence\":null," +
|
||||
"\"weight\":null," +
|
||||
"\"score-final\":true," +
|
||||
"\"score-magnitude\":\"1\"," +
|
||||
"\"score-direction\":\"1\"," +
|
||||
"\"estimated-value\":\"1113.2484\"," +
|
||||
"\"tag\":null}";
|
||||
|
||||
private string jsonWithExpectedOutputFromMissingCreatedTimeValue = @"{""id"":""e02be50f56a8496b9ba995d19a904ada"",""groupId"":""a02be50f56a8496b9ba995d19a904ada"",
|
||||
""sourceModel"":""mySourceModel-1"",""generatedTime"":1520711961.00055,""createdTime"":1520711961.00055,""closeTime"":1520711961.00055,""symbol"":""BTCUSD XJ"",""ticker"":
|
||||
""BTCUSD"",""type"":""price"",""reference"":9143.53,""referenceValueFinal"":9243.53,""direction"":""up"",""period"":5.0,""magnitude"":""0.025"",""confidence"":null,
|
||||
""weight"":null,""scoreIsFinal"":true,""scoreMagnitude"":""1"",""scoreDirection"":""1"",""estimatedValue"":""1113.2484"",""tag"":null}".ReplaceLineEndings(string.Empty);
|
||||
|
||||
private string jsonWithTag = @"{""id"":""e02be50f56a8496b9ba995d19a904ada"",""groupId"":""a02be50f56a8496b9ba995d19a904ada"",""sourceModel"":""mySourceModel-1"",
|
||||
""generatedTime"":1520711961.00055,""createdTime"":1520711961.00055,""closeTime"":1520711961.00055,""symbol"":""BTCUSD XJ"",""ticker"":""BTCUSD"",""type"":
|
||||
""price"",""reference"":9143.53,""referenceValueFinal"":9243.53,""direction"":""up"",""period"":5.0,""magnitude"":null,""confidence"":null,""weight"":null,
|
||||
""scoreIsFinal"":true,""scoreMagnitude"":""1"",""scoreDirection"":""1"",""estimatedValue"":""1113.2484"",""tag"":""additional information""}".ReplaceLineEndings(string.Empty);
|
||||
private const string jsonWithTagBackwardsCompatible =
|
||||
"{" +
|
||||
"\"id\":\"e02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"group-id\":\"a02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"source-model\":\"mySourceModel-1\"," +
|
||||
"\"generated-time\":1520711961.00055," +
|
||||
"\"created-time\":1520711961.00055," +
|
||||
"\"close-time\":1520711961.00055," +
|
||||
"\"symbol\":\"BTCUSD XJ\"," +
|
||||
"\"ticker\":\"BTCUSD\"," +
|
||||
"\"type\":\"price\"," +
|
||||
"\"reference\":9143.53," +
|
||||
"\"reference-final\":9243.53," +
|
||||
"\"direction\":\"up\"," +
|
||||
"\"period\":5.0," +
|
||||
"\"magnitude\":null," +
|
||||
"\"confidence\":null," +
|
||||
"\"weight\":null," +
|
||||
"\"score-final\":true," +
|
||||
"\"score-magnitude\":\"1\"," +
|
||||
"\"score-direction\":\"1\"," +
|
||||
"\"estimated-value\":\"1113.2484\"," +
|
||||
"\"tag\":\"additional information\"}";
|
||||
|
||||
private string jsonWithoutTag = @"{""id"":""e02be50f56a8496b9ba995d19a904ada"",""groupId"":""a02be50f56a8496b9ba995d19a904ada"",
|
||||
""sourceModel"":""mySourceModel-1"",""generatedTime"":1520711961.00055,""createdTime"":1520711961.00055,""closeTime"":1520711961.00055,""symbol"":""BTCUSD XJ"",
|
||||
""ticker"":""BTCUSD"",""type"":""price"",""reference"":9143.53,""referenceValueFinal"":9243.53,""direction"":""up"",""period"":5.0,""magnitude"":null,
|
||||
""confidence"":null,""weight"":null,""scoreIsFinal"":true,""scoreMagnitude"":""1"",""scoreDirection"":""1"",""estimatedValue"":""1113.2484"",""tag"":null}".ReplaceLineEndings(string.Empty);
|
||||
|
||||
private const string jsonWithoutTagBackwardsCompatible =
|
||||
"{" +
|
||||
"\"id\":\"e02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"group-id\":\"a02be50f56a8496b9ba995d19a904ada\"," +
|
||||
"\"source-model\":\"mySourceModel-1\"," +
|
||||
"\"generated-time\":1520711961.00055," +
|
||||
"\"created-time\":1520711961.00055," +
|
||||
"\"close-time\":1520711961.00055," +
|
||||
"\"symbol\":\"BTCUSD XJ\"," +
|
||||
"\"ticker\":\"BTCUSD\"," +
|
||||
"\"type\":\"price\"," +
|
||||
"\"reference\":9143.53," +
|
||||
"\"reference-final\":9243.53," +
|
||||
"\"direction\":\"up\"," +
|
||||
"\"period\":5.0," +
|
||||
"\"magnitude\":null," +
|
||||
"\"confidence\":null," +
|
||||
"\"weight\":null," +
|
||||
"\"score-final\":true," +
|
||||
"\"score-magnitude\":\"1\"," +
|
||||
"\"score-direction\":\"1\"," +
|
||||
"\"estimated-value\":\"1113.2484\"," +
|
||||
"\"tag\":null}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.Algorithm.Framework.Alphas;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
class TestEmaCrossAlphaModel : EmaCrossAlphaModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the _symbolDataBySymbol dictionary from EmaCrossAlphaModel
|
||||
/// </summary>
|
||||
/// <returns>_symbolDataBySymbol dictionary from EmaCrossAlphaModel</returns>
|
||||
public Dictionary<Symbol, SymbolData> GetSymbolData()
|
||||
{
|
||||
return SymbolDataBySymbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.Algorithm.Framework.Alphas;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Tests.Algorithm.Framework.Alphas
|
||||
{
|
||||
class TestMacdAlphaModel: MacdAlphaModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the _symbolData dictionary from MacdAlphaModel
|
||||
/// </summary>
|
||||
/// <returns>_symbolData dictionary from MacdAlphaModel</returns>
|
||||
public Dictionary<Symbol, SymbolData> GetSymbolData()
|
||||
{
|
||||
return _symbolData;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user