Files
quantconnect--lean/Tests/Common/Util/ExtensionsTests.cs
Martin Molinero 168fb98e20 Fix Turnover Ratio for Futures/CFDs
- `Futures` and `CFDs` sales value will use `ContractMultiplier` as the
rest of the securities.
- `FitnessScore` values will be truncated, not rounded, to 3 decimal places.
- Reducing code duplication for calculating the
`CompoundingAnnualPerformance`
2019-06-06 20:06:54 -03:00

796 lines
32 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 System.Globalization;
using System.Linq;
using Newtonsoft.Json;
using NUnit.Framework;
using Python.Runtime;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Orders;
using QuantConnect.Securities;
namespace QuantConnect.Tests.Common.Util
{
[TestFixture]
public class ExtensionsTests
{
[Test]
public void IsSubclassOfGenericWorksWorksForNonGenericType()
{
Assert.IsTrue(typeof(Derived2).IsSubclassOfGeneric(typeof(Derived1)));
}
[Test]
public void IsSubclassOfGenericWorksForGenericTypeWithParameter()
{
Assert.IsTrue(typeof(Derived1).IsSubclassOfGeneric(typeof(Super<int>)));
Assert.IsFalse(typeof(Derived1).IsSubclassOfGeneric(typeof(Super<bool>)));
}
[Test]
public void IsSubclassOfGenericWorksForGenericTypeDefinitions()
{
Assert.IsTrue(typeof(Derived1).IsSubclassOfGeneric(typeof(Super<>)));
Assert.IsTrue(typeof(Derived2).IsSubclassOfGeneric(typeof(Super<>)));
}
[Test]
public void DateTimeRoundDownFullDayDoesntRoundDownByDay()
{
var date = new DateTime(2000, 01, 01);
var rounded = date.RoundDown(TimeSpan.FromDays(1));
Assert.AreEqual(date, rounded);
}
[Test]
public void GetBetterTypeNameHandlesRecursiveGenericTypes()
{
var type = typeof (Dictionary<List<int>, Dictionary<int, string>>);
const string expected = "Dictionary<List<Int32>, Dictionary<Int32, String>>";
var actual = type.GetBetterTypeName();
Assert.AreEqual(expected, actual);
}
[Test]
public void ExchangeRoundDownSkipsWeekends()
{
var time = new DateTime(2015, 05, 02, 18, 01, 00);
var expected = new DateTime(2015, 05, 01);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.FXCM, null, SecurityType.Forex);
var exchangeRounded = time.ExchangeRoundDown(Time.OneDay, hours, false);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void ExchangeRoundDownHandlesMarketOpenTime()
{
var time = new DateTime(2016, 1, 25, 9, 31, 0);
var expected = time.Date;
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.USA, null, SecurityType.Equity);
var exchangeRounded = time.ExchangeRoundDown(Time.OneDay, hours, false);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void ConvertToSkipsDiscontinuitiesBecauseOfDaylightSavingsStart_AddingOneHour()
{
var expected = new DateTime(2014, 3, 9, 3, 0, 0);
var time = new DateTime(2014, 3, 9, 2, 0, 0).ConvertTo(TimeZones.NewYork, TimeZones.NewYork);
var time2 = new DateTime(2014, 3, 9, 2, 0, 1).ConvertTo(TimeZones.NewYork, TimeZones.NewYork);
Assert.AreEqual(expected, time);
Assert.AreEqual(expected, time2);
}
[Test]
public void ConvertToIgnoreDaylightSavingsEnd_SubtractingOneHour()
{
var time1Expected = new DateTime(2014, 11, 2, 1, 59, 59);
var time2Expected = new DateTime(2014, 11, 2, 2, 0, 0);
var time3Expected = new DateTime(2014, 11, 2, 2, 0, 1);
var time1 = time1Expected.ConvertTo(TimeZones.NewYork, TimeZones.NewYork);
var time2 = time2Expected.ConvertTo(TimeZones.NewYork, TimeZones.NewYork);
var time3 = time3Expected.ConvertTo(TimeZones.NewYork, TimeZones.NewYork);
Assert.AreEqual(time1Expected, time1);
Assert.AreEqual(time2Expected, time2);
Assert.AreEqual(time3Expected, time3);
}
[Test]
public void ExchangeRoundDownInTimeZoneSkipsWeekends()
{
// moment before EST market open in UTC (time + one day)
var time = new DateTime(2017, 10, 01, 9, 29, 59).ConvertToUtc(TimeZones.NewYork);
var expected = new DateTime(2017, 09, 29).ConvertFromUtc(TimeZones.NewYork);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.USA, null, SecurityType.Equity);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneDay, hours, TimeZones.Utc, false);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
// This unit test reproduces a fixed infinite loop situation, due to a daylight saving time change, in ExchangeRoundDownInTimeZone, GH issue 2368.
public void ExchangeRoundDownInTimeZoneCorrectValuesAroundDaylightTimeChanges_AddingOneHour_UTC()
{
var time = new DateTime(2014, 3, 9, 16, 0, 1);
var expected = new DateTime(2014, 3, 7, 16, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, null, SecurityType.Forex);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneHour, hours, TimeZones.Utc, false);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
// This unit test reproduces a fixed infinite loop situation, due to a daylight saving time change, in ExchangeRoundDownInTimeZone, GH issue 2368.
public void ExchangeRoundDownInTimeZoneCorrectValuesAroundDaylightTimeChanges_SubtractingOneHour_UTC()
{
var time = new DateTime(2014, 11, 2, 2, 0, 1);
var expected = new DateTime(2014, 10, 31, 16, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, null, SecurityType.Forex);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneHour, hours, TimeZones.Utc, false);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void ExchangeRoundDownInTimeZoneCorrectValuesAroundDaylightTimeChanges_AddingOneHour_ExtendedHours_UTC()
{
var time = new DateTime(2014, 3, 9, 2, 0, 1);
var expected = new DateTime(2014, 3, 9, 2, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.GDAX, null, SecurityType.Crypto);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneHour, hours, TimeZones.Utc, true);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void ExchangeRoundDownInTimeZoneCorrectValuesAroundDaylightTimeChanges_SubtractingOneHour_ExtendedHours_UTC()
{
var time = new DateTime(2014, 11, 2, 2, 0, 1);
var expected = new DateTime(2014, 11, 2, 2, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.GDAX, null, SecurityType.Crypto);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneHour, hours, TimeZones.Utc, true);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void RoundDownInTimeZoneReturnsCorrectValuesAroundDaylightTimeChanges_AddingOneHour_UTC()
{
var timeAt = new DateTime(2014, 3, 9, 2, 0, 0);
var timeAfter = new DateTime(2014, 3, 9, 2, 0, 1);
var timeBefore = new DateTime(2014, 3, 9, 1, 59, 59);
var timeAfterDaylightTimeChanges = new DateTime(2014, 3, 9, 3, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, null, SecurityType.Forex);
var exchangeRoundedAt = timeAt.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.Utc);
var exchangeRoundedAfter = timeAfter.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.Utc);
var exchangeRoundedBefore = timeBefore.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.Utc);
var exchangeRoundedAfterDaylightTimeChanges = timeAfterDaylightTimeChanges.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.Utc);
var expected = new DateTime(2014, 3, 9, 3, 0, 0);
Assert.AreEqual(expected, exchangeRoundedAt);
Assert.AreEqual(expected, exchangeRoundedAfter);
Assert.AreEqual(timeBefore, exchangeRoundedBefore);
Assert.AreEqual(expected, exchangeRoundedAfterDaylightTimeChanges);
}
[Test]
public void RoundDownInTimeZoneReturnsCorrectValuesAroundDaylightTimeChanges_SubtractingOneHour_UTC()
{
var timeAt = new DateTime(2014, 11, 2, 2, 0, 0);
var timeAfter = new DateTime(2014, 11, 2, 2, 0, 1);
var timeBefore = new DateTime(2014, 11, 2, 1, 59, 59);
var timeAfterDaylightTimeChanges = new DateTime(2014, 11, 2, 3, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, null, SecurityType.Forex);
var exchangeRoundedAt = timeAt.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.Utc);
var exchangeRoundedAfter = timeAfter.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.Utc);
var exchangeRoundedBefore = timeBefore.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.Utc);
var exchangeRoundedAfterDaylightTimeChanges = timeAfterDaylightTimeChanges.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.Utc);
Assert.AreEqual(timeAt, exchangeRoundedAt);
Assert.AreEqual(timeAfter, exchangeRoundedAfter);
Assert.AreEqual(timeBefore, exchangeRoundedBefore);
Assert.AreEqual(timeAfterDaylightTimeChanges, exchangeRoundedAfterDaylightTimeChanges);
}
[Test]
public void ExchangeRoundDownInTimeZoneCorrectValuesAroundDaylightTimeChanges_AddingOneHour_NewYork()
{
var time = new DateTime(2014, 3, 9, 16, 0, 1);
var expected = new DateTime(2014, 3, 7, 16, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, null, SecurityType.Forex);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneHour, hours, TimeZones.NewYork, false);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void ExchangeRoundDownInTimeZoneCorrectValuesAroundDaylightTimeChanges_SubtractingOneHour_NewYork()
{
var time = new DateTime(2014, 11, 2, 2, 0, 1);
var expected = new DateTime(2014, 10, 31, 16, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, null, SecurityType.Forex);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneHour, hours, TimeZones.NewYork, false);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void ExchangeRoundDownInTimeZoneCorrectValuesAroundDaylightTimeChanges_AddingOneHour_ExtendedHours_NewYork()
{
var time = new DateTime(2014, 3, 9, 2, 0, 1);
var expected = new DateTime(2014, 3, 9, 2, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.GDAX, null, SecurityType.Crypto);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneHour, hours, TimeZones.NewYork, true);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void ExchangeRoundDownInTimeZoneCorrectValuesAroundDaylightTimeChanges_SubtractingOneHour_ExtendedHours_NewYork()
{
var time = new DateTime(2014, 11, 2, 2, 0, 1);
var expected = new DateTime(2014, 11, 2, 2, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.GDAX, null, SecurityType.Crypto);
var exchangeRounded = time.ExchangeRoundDownInTimeZone(Time.OneHour, hours, TimeZones.NewYork, true);
Assert.AreEqual(expected, exchangeRounded);
}
[Test]
public void RoundDownInTimeZoneReturnsCorrectValuesAroundDaylightTimeChanges_AddingOneHour_NewYork()
{
var timeAt = new DateTime(2014, 3, 9, 2, 0, 0);
var timeAfter = new DateTime(2014, 3, 9, 2, 0, 1);
var timeBefore = new DateTime(2014, 3, 9, 1, 59, 59);
var timeAfterDaylightTimeChanges = new DateTime(2014, 3, 9, 3, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, null, SecurityType.Forex);
var exchangeRoundedAt = timeAt.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.NewYork);
var exchangeRoundedAfter = timeAfter.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.NewYork);
var exchangeRoundedBefore = timeBefore.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.NewYork);
var exchangeRoundedAfterDaylightTimeChanges = timeAfterDaylightTimeChanges.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.NewYork);
var expected = new DateTime(2014, 3, 9, 3, 0, 0);
Assert.AreEqual(expected, exchangeRoundedAt);
Assert.AreEqual(expected, exchangeRoundedAfter);
Assert.AreEqual(timeBefore, exchangeRoundedBefore);
Assert.AreEqual(expected, exchangeRoundedAfterDaylightTimeChanges);
}
[Test]
public void RoundDownInTimeZoneReturnsCorrectValuesAroundDaylightTimeChanges_SubtractingOneHour_NewYork()
{
var timeAt = new DateTime(2014, 11, 2, 2, 0, 0);
var timeAfter = new DateTime(2014, 11, 2, 2, 0, 1);
var timeBefore = new DateTime(2014, 11, 2, 1, 59, 59);
var timeAfterDaylightTimeChanges = new DateTime(2014, 11, 2, 3, 0, 0);
var hours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.Oanda, null, SecurityType.Forex);
var exchangeRoundedAt = timeAt.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.NewYork);
var exchangeRoundedAfter = timeAfter.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.NewYork);
var exchangeRoundedBefore = timeBefore.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.NewYork);
var exchangeRoundedAfterDaylightTimeChanges = timeAfterDaylightTimeChanges.RoundDownInTimeZone(Time.OneSecond, hours.TimeZone, TimeZones.NewYork);
Assert.AreEqual(timeAt, exchangeRoundedAt);
Assert.AreEqual(timeAfter, exchangeRoundedAfter);
Assert.AreEqual(timeBefore, exchangeRoundedBefore);
Assert.AreEqual(timeAfterDaylightTimeChanges, exchangeRoundedAfterDaylightTimeChanges);
}
[Test]
public void ConvertsInt32FromString()
{
const string input = "12345678";
var value = input.ToInt32();
Assert.AreEqual(12345678, value);
}
[Test]
public void ConvertsInt32FromStringWithDecimalTruncation()
{
const string input = "12345678.9";
var value = input.ToInt32();
Assert.AreEqual(12345678, value);
}
[Test]
public void ConvertsInt64FromString()
{
const string input = "12345678900";
var value = input.ToInt64();
Assert.AreEqual(12345678900, value);
}
[Test]
public void ConvertsInt64FromStringWithDecimalTruncation()
{
const string input = "12345678900.12";
var value = input.ToInt64();
Assert.AreEqual(12345678900, value);
}
[Test]
public void ConvertsDecimalFromString()
{
const string input = "123.45678";
var value = input.ToDecimal();
Assert.AreEqual(123.45678m, value);
}
[Test]
public void ConvertsDecimalFromStringWithExtraWhiteSpace()
{
const string input = " 123.45678 ";
var value = input.ToDecimal();
Assert.AreEqual(123.45678m, value);
}
[Test]
public void ConvertsDecimalFromIntStringWithExtraWhiteSpace()
{
const string input = " 12345678 ";
var value = input.ToDecimal();
Assert.AreEqual(12345678m, value);
}
[Test]
public void ConvertsZeroDecimalFromString()
{
const string input = "0.45678";
var value = input.ToDecimal();
Assert.AreEqual(0.45678m, value);
}
[Test]
public void ConvertsOneNumberDecimalFromString()
{
const string input = "1.45678";
var value = input.ToDecimal();
Assert.AreEqual(1.45678m, value);
}
[Test]
public void ConvertsZeroDecimalValueFromString()
{
const string input = "0";
var value = input.ToDecimal();
Assert.AreEqual(0m, value);
}
[Test]
public void ConvertsEmptyDecimalValueFromString()
{
const string input = "";
var value = input.ToDecimal();
Assert.AreEqual(0m, value);
}
[Test]
public void ConvertsNegativeDecimalFromString()
{
const string input = "-123.45678";
var value = input.ToDecimal();
Assert.AreEqual(-123.45678m, value);
}
[Test]
public void ConvertsNegativeDecimalFromStringWithExtraWhiteSpace()
{
const string input = " -123.45678 ";
var value = input.ToDecimal();
Assert.AreEqual(-123.45678m, value);
}
[Test]
public void ConvertsNegativeDecimalFromIntStringWithExtraWhiteSpace()
{
const string input = " -12345678 ";
var value = input.ToDecimal();
Assert.AreEqual(-12345678m, value);
}
[Test]
public void ConvertsNegativeZeroDecimalFromString()
{
const string input = "-0.45678";
var value = input.ToDecimal();
Assert.AreEqual(-0.45678m, value);
}
[Test]
public void ConvertsNegavtiveOneNumberDecimalFromString()
{
const string input = "-1.45678";
var value = input.ToDecimal();
Assert.AreEqual(-1.45678m, value);
}
[Test]
public void ConvertsNegativeZeroDecimalValueFromString()
{
const string input = "-0";
var value = input.ToDecimal();
Assert.AreEqual(-0m, value);
}
[Test]
public void ConvertsTimeSpanFromString()
{
const string input = "16:00";
var timespan = input.ConvertTo<TimeSpan>();
Assert.AreEqual(TimeSpan.FromHours(16), timespan);
}
[Test]
public void ConvertsDictionaryFromString()
{
var expected = new Dictionary<string, int> {{"a", 1}, {"b", 2}};
var input = JsonConvert.SerializeObject(expected);
var actual = input.ConvertTo<Dictionary<string, int>>();
CollectionAssert.AreEqual(expected, actual);
}
[Test]
public void DictionaryAddsItemToExistsList()
{
const int key = 0;
var list = new List<int> {1, 2};
var dictionary = new Dictionary<int, List<int>> {{key, list}};
Extensions.Add(dictionary, key, 3);
Assert.AreEqual(3, list.Count);
Assert.AreEqual(3, list[2]);
}
[Test]
public void DictionaryAddCreatesNewList()
{
const int key = 0;
var dictionary = new Dictionary<int, List<int>>();
Extensions.Add(dictionary, key, 1);
Assert.IsTrue(dictionary.ContainsKey(key));
var list = dictionary[key];
Assert.AreEqual(1, list.Count);
Assert.AreEqual(1, list[0]);
}
[Test]
public void SafeDecimalCasts()
{
var input = 2d;
var output = input.SafeDecimalCast();
Assert.AreEqual(2m, output);
}
[Test]
public void SafeDecimalCastRespectsUpperBound()
{
var input = (double) decimal.MaxValue;
var output = input.SafeDecimalCast();
Assert.AreEqual(decimal.MaxValue, output);
}
[Test]
public void SafeDecimalCastRespectsLowerBound()
{
var input = (double) decimal.MinValue;
var output = input.SafeDecimalCast();
Assert.AreEqual(decimal.MinValue, output);
}
[Test]
[TestCase(1.200, "1.2")]
[TestCase(1200, "1200")]
[TestCase(123.456, "123.456")]
public void NormalizeDecimalReturnsNoTrailingZeros(decimal input, string expectedOutput)
{
var output = input.Normalize();
Assert.AreEqual(expectedOutput, output.ToString(CultureInfo.InvariantCulture));
}
[Test]
public void RoundsDownInTimeZone()
{
var dataTimeZone = TimeZones.Utc;
var exchangeTimeZone = TimeZones.EasternStandard;
var time = new DateTime(2000, 01, 01).ConvertTo(dataTimeZone, exchangeTimeZone);
var roundedTime = time.RoundDownInTimeZone(Time.OneDay, exchangeTimeZone, dataTimeZone);
Assert.AreEqual(time, roundedTime);
}
[Test]
public void GetStringBetweenCharsTests()
{
const string expected = "python3.6";
// Different characters cases
var input = "[ python3.6 ]";
var actual = input.GetStringBetweenChars('[', ']');
Assert.AreEqual(expected, actual);
input = "[ python3.6 ] [ python2.7 ]";
actual = input.GetStringBetweenChars('[', ']');
Assert.AreEqual(expected, actual);
input = "[ python2.7 [ python3.6 ] ]";
actual = input.GetStringBetweenChars('[', ']');
Assert.AreEqual(expected, actual);
// Same character cases
input = "\'python3.6\'";
actual = input.GetStringBetweenChars('\'', '\'');
Assert.AreEqual(expected, actual);
input = "\' python3.6 \' \' python2.7 \'";
actual = input.GetStringBetweenChars('\'', '\'');
Assert.AreEqual(expected, actual);
// In this case, it is not equal
input = "\' python2.7 \' python3.6 \' \'";
actual = input.GetStringBetweenChars('\'', '\'');
Assert.AreNotEqual(expected, actual);
}
[Test]
public void PyObjectTryConvertQuoteBar()
{
// Wrap a QuoteBar around a PyObject and convert it back
var value = ConvertToPyObject(new QuoteBar());
QuoteBar quoteBar;
var canConvert = value.TryConvert(out quoteBar);
Assert.IsTrue(canConvert);
Assert.IsNotNull(quoteBar);
Assert.IsAssignableFrom<QuoteBar>(quoteBar);
}
[Test]
public void PyObjectTryConvertSMA()
{
// Wrap a SimpleMovingAverage around a PyObject and convert it back
var value = ConvertToPyObject(new SimpleMovingAverage(14));
IndicatorBase<IndicatorDataPoint> indicatorBaseDataPoint;
var canConvert = value.TryConvert(out indicatorBaseDataPoint);
Assert.IsTrue(canConvert);
Assert.IsNotNull(indicatorBaseDataPoint);
Assert.IsAssignableFrom<SimpleMovingAverage>(indicatorBaseDataPoint);
}
[Test]
public void PyObjectTryConvertATR()
{
// Wrap a AverageTrueRange around a PyObject and convert it back
var value = ConvertToPyObject(new AverageTrueRange(14, MovingAverageType.Simple));
IndicatorBase<IBaseDataBar> indicatorBaseDataBar;
var canConvert = value.TryConvert(out indicatorBaseDataBar);
Assert.IsTrue(canConvert);
Assert.IsNotNull(indicatorBaseDataBar);
Assert.IsAssignableFrom<AverageTrueRange>(indicatorBaseDataBar);
}
[Test]
public void PyObjectTryConvertAD()
{
// Wrap a AccumulationDistribution around a PyObject and convert it back
var value = ConvertToPyObject(new AccumulationDistribution("AD"));
IndicatorBase<TradeBar> indicatorBaseTradeBar;
var canConvert = value.TryConvert(out indicatorBaseTradeBar);
Assert.IsTrue(canConvert);
Assert.IsNotNull(indicatorBaseTradeBar);
Assert.IsAssignableFrom<AccumulationDistribution>(indicatorBaseTradeBar);
}
[Test]
public void PyObjectTryConvertSymbolArray()
{
PyObject value;
using (Py.GIL())
{
// Wrap a Symbol Array around a PyObject and convert it back
value = new PyList(new[] { Symbols.SPY.ToPython(), Symbols.AAPL.ToPython() });
}
Symbol[] symbols;
var canConvert = value.TryConvert(out symbols);
Assert.IsTrue(canConvert);
Assert.IsNotNull(symbols);
Assert.IsAssignableFrom<Symbol[]>(symbols);
}
[Test]
public void PyObjectTryConvertFailCSharp()
{
// Try to convert a AccumulationDistribution as a QuoteBar
var value = ConvertToPyObject(new AccumulationDistribution("AD"));
QuoteBar quoteBar;
bool canConvert = value.TryConvert(out quoteBar);
Assert.IsFalse(canConvert);
Assert.IsNull(quoteBar);
}
[Test]
public void PyObjectTryConvertFailPython()
{
using (Py.GIL())
{
// Try to convert a python object as a IndicatorBase<TradeBar>
var locals = new PyDict();
PythonEngine.Exec("class A:\n pass", null, locals.Handle);
var value = locals.GetItem("A").Invoke();
IndicatorBase<TradeBar> indicatorBaseTradeBar;
bool canConvert = value.TryConvert(out indicatorBaseTradeBar);
Assert.IsFalse(canConvert);
Assert.IsNull(indicatorBaseTradeBar);
}
}
[Test]
[TestCase("coarseSelector = lambda coarse: [ x.Symbol for x in coarse if x.Price % 2 == 0 ]")]
[TestCase("def coarseSelector(coarse): return [ x.Symbol for x in coarse if x.Price % 2 == 0 ]")]
public void PyObjectTryConvertToFunc(string code)
{
Func<IEnumerable<CoarseFundamental>, Symbol[]> coarseSelector;
using (Py.GIL())
{
var locals = new PyDict();
PythonEngine.Exec(code, null, locals.Handle);
var pyObject = locals.GetItem("coarseSelector");
pyObject.TryConvertToDelegate(out coarseSelector);
}
var coarse = Enumerable
.Range(0, 9)
.Select(x => new CoarseFundamental { Symbol = Symbol.Create(x.ToString(), SecurityType.Equity, Market.USA), Value = x });
var symbols = coarseSelector(coarse);
Assert.AreEqual(5, symbols.Length);
foreach (var symbol in symbols)
{
var price = Convert.ToInt32(symbol.Value);
Assert.AreEqual(0, price % 2);
}
}
[Test]
public void PyObjectTryConvertToAction1()
{
Action<int> action;
using (Py.GIL())
{
var locals = new PyDict();
PythonEngine.Exec("def raise_number(a): raise ValueError(a)", null, locals.Handle);
var pyObject = locals.GetItem("raise_number");
pyObject.TryConvertToDelegate(out action);
}
try
{
action(2);
Assert.Fail();
}
catch (PythonException e)
{
Assert.AreEqual($"ValueError : {2}", e.Message);
}
}
[Test]
public void PyObjectTryConvertToAction2()
{
Action<int, decimal> action;
using (Py.GIL())
{
var locals = new PyDict();
PythonEngine.Exec("def raise_number(a, b): raise ValueError(a * b)", null, locals.Handle);
var pyObject = locals.GetItem("raise_number");
pyObject.TryConvertToDelegate(out action);
}
try
{
action(2, 3m);
Assert.Fail();
}
catch (PythonException e)
{
Assert.AreEqual("ValueError : 6.0", e.Message);
}
}
[Test]
public void PyObjectTryConvertToNonDelegateFail()
{
int action;
using (Py.GIL())
{
var locals = new PyDict();
PythonEngine.Exec("def raise_number(a, b): raise ValueError(a * b)", null, locals.Handle);
var pyObject = locals.GetItem("raise_number");
Assert.Throws<ArgumentException>(() => pyObject.TryConvertToDelegate(out action));
}
}
[Test]
public void BatchByDoesNotDropItems()
{
var list = new List<int> {1, 2, 3, 4, 5};
var by2 = list.BatchBy(2).ToList();
Assert.AreEqual(3, by2.Count);
Assert.AreEqual(2, by2[0].Count);
Assert.AreEqual(2, by2[1].Count);
Assert.AreEqual(1, by2[2].Count);
CollectionAssert.AreEqual(list, by2.SelectMany(x => x));
}
[Test]
public void ToOrderTicketCreatesCorrectTicket()
{
var orderRequest = new SubmitOrderRequest(OrderType.Limit, SecurityType.Equity, Symbols.USDJPY, 1000, 0, 1.11m, DateTime.Now, "Pepe");
var order = Order.CreateOrder(orderRequest);
order.Status = OrderStatus.Submitted;
order.Id = 11;
var orderTicket = order.ToOrderTicket(null);
Assert.AreEqual(order.Id, orderTicket.OrderId);
Assert.AreEqual(order.Quantity, orderTicket.Quantity);
Assert.AreEqual(order.Status, orderTicket.Status);
Assert.AreEqual(order.Type, orderTicket.OrderType);
Assert.AreEqual(order.Symbol, orderTicket.Symbol);
Assert.AreEqual(order.Tag, orderTicket.Tag);
Assert.AreEqual(order.Time, orderTicket.Time);
Assert.AreEqual(order.SecurityType, orderTicket.SecurityType);
}
[Test]
public void DecimalTruncateTo3DecimalPlaces()
{
var value = 10.999999m;
Assert.AreEqual(10.999m, value.TruncateTo3DecimalPlaces());
}
private PyObject ConvertToPyObject(object value)
{
using (Py.GIL())
{
return value.ToPython();
}
}
private class Super<T>
{
}
private class Derived1 : Super<int>
{
}
private class Derived2 : Derived1
{
}
}
}