Skip to content

Commit

Permalink
Added main feature and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
D1mi3 committed Feb 22, 2024
1 parent 387eae9 commit c2147b8
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
35 changes: 35 additions & 0 deletions Common/Securities/SecurityCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
using QuantConnect.Data.Market;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using QuantConnect.Python;
using System.Reflection;
using Python.Runtime;

namespace QuantConnect.Securities
{
Expand Down Expand Up @@ -224,6 +227,38 @@ protected virtual void ProcessDataPoint(BaseData data, bool cacheByType)
return;
}

var pythonData = data as PythonData;
if (pythonData != null && (_lastQuoteBarUpdate != data.EndTime || _lastOHLCUpdate != data.EndTime) && isDefaultDataType)
{
// Get matching pythonData and IBar properties
IDictionary<string, object> storage = pythonData.GetStorageDictionary();
PropertyInfo[] barProperties = typeof(IBar).GetProperties();
List<string> fieldsRequired = barProperties.Select(property => property.Name.ToLowerInvariant()).ToList();
var matches = storage.Where(kvp => fieldsRequired.Contains(kvp.Key) && kvp.Value != null) ;

IDictionary<string, decimal> validOHLC = new Dictionary<string, decimal>();

// Convert OHLC to decimal & update properties
if (matches.Count() == fieldsRequired.Count)
{
foreach (KeyValuePair<string, object> match in matches)
{
decimal.TryParse(match.Value.ToString(), out decimal result);
validOHLC.Add(match.Key, result);
}
_lastOHLCUpdate = data.EndTime;
if (validOHLC["open"] != 0) Open = validOHLC["open"];
if (validOHLC["high"] != 0) High = validOHLC["high"];
if (validOHLC["low"] != 0) Low = validOHLC["low"];
if (validOHLC["close"] != 0)
{
Price = validOHLC["close"];
Close = validOHLC["close"];
}
return;
}
}

var bar = data as IBar;
if (bar != null)
{
Expand Down
71 changes: 71 additions & 0 deletions Tests/Common/Securities/SecurityCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using NodaTime;
using NUnit.Framework;
using Python.Runtime;
using QuantConnect.Algorithm.CSharp;
using QuantConnect.Data;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Python;
using QuantConnect.Securities;
using QuantConnect.Tests.Common.Data.Fundamental;

Expand Down Expand Up @@ -359,6 +362,65 @@ public void AddDataEquity_OHLC_IgnoresQuoteBar()
Assert.AreEqual(110, securityCache.BidSize);
}

[Test]
public void AddDataEquity_OHLC_PythonData()
{
using (Py.GIL())
{
dynamic testModule = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
class CustomDataTest(PythonData):
def Reader(self, config, line, date, isLiveMode):
result = CustomDataTest()
result.Symbol = config.Symbol
result.Value = 3.7
result.Open = 3.1
result.High = 4.1
result.low = 2.0
result.close = 3.7
result.Time = datetime.strptime(""2022-05-05"", ""%Y-%m-%d"")
return result");

var data = GetDataFromModule(testModule);

var securityCache = new SecurityCache();
securityCache.AddData(data);

Assert.AreEqual(4.1, securityCache.High);
Assert.AreEqual(3.7, securityCache.Close);
Assert.AreEqual(2.0, securityCache.Low);
Assert.AreEqual(3.1, securityCache.Open);

testModule = PyModule.FromString("testModule",
@"
from AlgorithmImports import *
class CustomDataTest(PythonData):
def Reader(self, config, line, date, isLiveMode):
result = CustomDataTest()
result.Symbol = config.Symbol
result.Value = 3.7
result.Open = 3.1
result.High = 4
result.low = 2.0
result.Close = ""test""
result.Time = datetime.strptime(""2022-05-05"", ""%Y-%m-%d"")
return result");

data = GetDataFromModule(testModule);

securityCache.Reset();
securityCache.AddData(data);

Assert.AreEqual(4, securityCache.High);
Assert.AreEqual(0, securityCache.Close);
Assert.AreEqual(2.0, securityCache.Low);
Assert.AreEqual(3.1, securityCache.Open);
}
}

[Test]
[TestCaseSource(nameof(GetSecurityCacheInitialStates))]
public void AddDataWithSameEndTime_SetsQuoteBarValues(SecurityCache cache, SecuritySeedData seedType)
Expand Down Expand Up @@ -456,6 +518,15 @@ public void GetAllData_ReturnsListOfDataOnTargetCache()
Assert.AreEqual(2m, data[1].Ask);
}

private static BaseData GetDataFromModule(dynamic testModule)
{
var type = Extensions.CreateType(testModule.GetAttr("CustomDataTest"));
var customDataTest = new PythonData(testModule.GetAttr("CustomDataTest")());
var config = new SubscriptionDataConfig(type, Symbols.SPY, Resolution.Daily, DateTimeZone.Utc,
DateTimeZone.Utc, false, false, false, isCustom: true);
return customDataTest.Reader(config, "something", DateTime.UtcNow, false);
}

private void AddDataAndAssertChanges(SecurityCache cache, SecuritySeedData seedType, SecuritySeedData dataType, BaseData data, Dictionary<string, string> cacheToBaseDataPropertyMap = null)
{
var before = JObject.FromObject(cache);
Expand Down

0 comments on commit c2147b8

Please sign in to comment.