Files
quantconnect--lean/Tests/Common/Securities/DynamicSecurityDataTests.cs
T
2026-07-13 13:02:50 +08:00

390 lines
13 KiB
C#

/*
* 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.Collections.Generic;
using NUnit.Framework;
using Python.Runtime;
using QuantConnect.Data.Market;
using QuantConnect.Securities;
namespace QuantConnect.Tests.Common.Securities
{
[TestFixture]
public class DynamicSecurityDataTests
{
private SecurityCache _cache;
private RegisteredSecurityDataTypesProvider _dataTypesProvider;
[SetUp]
public void SetUp()
{
_cache = new SecurityCache();
_dataTypesProvider = new RegisteredSecurityDataTypesProvider();
_dataTypesProvider.RegisterType(typeof(TradeBar));
}
[TearDown]
public void TearDown()
{
_cache.Reset();
}
[Test]
public void StoreData_UsesTypeName_AsKey()
{
var data = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar>
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 15m, 10000)
}, typeof(TradeBar));
Assert.IsTrue(data.HasProperty(typeof(TradeBar).Name));
var arr = (IReadOnlyList<TradeBar>)data.GetProperty(typeof(TradeBar).Name);
Assert.AreEqual(1, arr.Count);
Assert.AreEqual(15, arr[0].Close);
}
[Test]
public void Get_UsesTypeName_AsKey_And_ReturnsLastItem()
{
var data = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar> {
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000),
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 2, 10000),
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 3, 10000)
}, typeof(TradeBar));
var item = data.Get<TradeBar>();
Assert.AreEqual(3, item.Close);
}
[Test]
public void GetAll_UsesTypeName_AsKey()
{
var data = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar> {
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000),
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 2, 10000),
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 3, 10000)
}, typeof(TradeBar));
var arr = data.GetAll<TradeBar>();
Assert.AreEqual(3, arr.Count);
Assert.AreEqual(1, arr[0].Close);
}
[Test]
public void AccessesDataDynamically()
{
var securityData = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar> {
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000),
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 2, 10000),
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 3, 10000)
}, typeof(TradeBar));
dynamic dynamicSecurityData = securityData;
var tradeBars = dynamicSecurityData.TradeBar;
Assert.IsInstanceOf<IReadOnlyList<TradeBar>>(tradeBars);
}
[Test]
public void DataCanNotBeSetDynamically()
{
var securityData = new DynamicSecurityData(_dataTypesProvider, _cache);
var data = new List<TradeBar> {
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000)
};
dynamic dynamicSecurityData = securityData;
Assert.Throws<InvalidOperationException>(() =>
{
dynamicSecurityData.TradeBar = data;
});
}
[Test]
public void AccessingPropertyThatDoesNotExists_ThrowsKeyNotFoundException_WhenNotIncludedInRegisteredTypes()
{
var registeredTypes = new RegisteredSecurityDataTypesProvider();
dynamic securityData = new DynamicSecurityData(registeredTypes, _cache);
Assert.Throws<KeyNotFoundException>(() =>
{
var _ = securityData.NotFoundProperty;
});
}
[Test]
public void AccessPropertyThatDoesNotExists_ReturnsEmptyList_WhenTypeIsIncludedInRegisteredTypes()
{
var registeredTypes = new RegisteredSecurityDataTypesProvider();
registeredTypes.RegisterType(typeof(TradeBar));
dynamic securityData = new DynamicSecurityData(registeredTypes, _cache);
var tradeBars = securityData.TradeBar;
Assert.IsInstanceOf<List<TradeBar>>(tradeBars);
Assert.IsEmpty(tradeBars);
}
[Test]
public void Py_StoreData_GetProperty()
{
var data = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar>
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000)
}, typeof(TradeBar));
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.GetProperty(""TradeBar"")
if len(data) != 1:
raise Exception('Unexpected length')
if data[0].Close != 1:
raise Exception('Unexpected value')").GetAttr("Test");
Assert.DoesNotThrow(() => test(data));
}
}
[Test]
public void Py_StoreData_HasProperty()
{
var data = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar>
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000)
}, typeof(TradeBar));
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.HasProperty(""TradeBar"")
if not data:
raise Exception('Unexpected HasProperty result')").GetAttr("Test");
Assert.DoesNotThrow(() => test(data));
}
}
[Test]
public void Py_StoreData_Get_UsesTypeName()
{
var data = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar>
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000)
}, typeof(TradeBar));
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.Get(TradeBar)
if data.Close != 1:
raise Exception('Unexpected value')").GetAttr("Test");
Assert.DoesNotThrow(() => test(data));
}
}
[Test]
public void Py_StoreData_GetAll_UsesTypeName()
{
var data = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar>
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000)
}, typeof(TradeBar));
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.GetAll(TradeBar)
if len(data) != 1:
raise Exception('Unexpected length')
if data[0].Close != 1:
raise Exception('Unexpected value')").GetAttr("Test");
Assert.DoesNotThrow(() => test(data));
}
}
[Test]
public void Py_Get_UsesTypeName_AsKey_And_ReturnsLastItem()
{
var data = new DynamicSecurityData(_dataTypesProvider, _cache);
_cache.StoreData(new List<TradeBar>
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 1, 10000),
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 3, 10000)
}, typeof(TradeBar));
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.Get(TradeBar)
if data.Close != 3:
raise Exception('Unexpected value')").GetAttr("Test");
Assert.DoesNotThrow(() => test(data));
}
}
[Test]
public void Py_GetAll_TradeBar()
{
var securityData = new DynamicSecurityData(_dataTypesProvider, _cache);
var data = new List<TradeBar>
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 15m, 10000)
};
_cache.StoreData(data, typeof(TradeBar));
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.GetAll(TradeBar)
if data[0].Low != 5:
raise Exception('Unexpected value')").GetAttr("Test");
Assert.DoesNotThrow(() => test(securityData));
}
}
[Test]
public void Py_Get_TradeBar()
{
var securityData = new DynamicSecurityData(_dataTypesProvider, _cache);
var data = new List<TradeBar>
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 15m, 10000)
};
_cache.StoreData(data, typeof(TradeBar));
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.Get(TradeBar)
if data.Low != 5:
raise Exception('Unexpected value')").GetAttr("Test");
Assert.DoesNotThrow(() => test(securityData));
}
}
[Test]
public void Py_Get_TradeBarArray()
{
var securityData = new DynamicSecurityData(_dataTypesProvider, _cache);
var data = new[]
{
new TradeBar(DateTime.UtcNow, Symbols.SPY, 10m, 20m, 5m, 15m, 10000)
};
_cache.StoreData(data, typeof(TradeBar));
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.Get(TradeBar)
if data.Low != 5:
raise Exception('Unexpected value')").GetAttr("Test");
Assert.DoesNotThrow(() => test(securityData));
}
}
[Test]
public void Py_GetTypeThatDoesNotExists_ThrowsKeyNotFoundException_WhenNotIncludedInRegisteredTypes()
{
var registeredTypes = new RegisteredSecurityDataTypesProvider();
dynamic securityData = new DynamicSecurityData(registeredTypes, _cache);
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.Get(TradeBar)").GetAttr("Test");
Assert.That(() => test(securityData),
Throws.InstanceOf<ClrBubbledException>().With.InnerException.InstanceOf<KeyNotFoundException>());
}
}
[Test]
public void Py_AccessPropertyThatDoesNotExists_ReturnsEmptyList_WhenTypeIsIncludedInRegisteredTypes()
{
var registeredTypes = new RegisteredSecurityDataTypesProvider();
registeredTypes.RegisterType(typeof(TradeBar));
dynamic securityData = new DynamicSecurityData(registeredTypes, _cache);
using (Py.GIL())
{
dynamic test = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
def Test(dynamicData):
data = dynamicData.GetAll(TradeBar)
if data is None:
raise Exception('Unexpected None value')
if len(data) != 0:
raise Exception('Unexpected length')").GetAttr("Test");
Assert.DoesNotThrow(() => test(securityData));
}
}
}
}