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

155 lines
6.1 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.Linq;
using System.Collections.Generic;
using NUnit.Framework;
using QuantConnect.Util;
using QuantConnect.Data.Market;
using QuantConnect.Algorithm;
using QuantConnect.Lean.Engine.Setup;
namespace QuantConnect.Tests.Common.Statistics
{
[TestFixture]
public class TrackingErrorTests
{
private List<TradeBar> _spy = new List<TradeBar>();
private List<TradeBar> _aapl = new List<TradeBar>();
private List<double> _spyPerformance = new List<double>();
private List<double> _aaplPerformance = new List<double>();
/// <summary>
/// Instance of QC Algorithm.
/// Use to get <see cref="Interfaces.IAlgorithmSettings.TradingDaysPerYear"/> for clear calculation in <seealso cref="QuantConnect.Statistics.Statistics.AnnualPerformance"/>
/// </summary>
private QCAlgorithm _algorithm;
[OneTimeSetUp]
public void GetData()
{
_algorithm = new QCAlgorithm();
BaseSetupHandler.SetBrokerageTradingDayPerYear(_algorithm);
var spy = Symbol.Create("SPY", SecurityType.Equity, Market.USA);
var spyPath = LeanData.GenerateZipFilePath(Globals.DataFolder, spy, new DateTime(2020, 3, 1), Resolution.Daily, TickType.Trade);
var spyConfig = new QuantConnect.Data.SubscriptionDataConfig(typeof(TradeBar), spy, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
var endDate = new DateTime(2020, 3, 8);
foreach (var line in QuantConnect.Compression.ReadLines(spyPath))
{
var bar = TradeBar.ParseEquity(spyConfig, line, DateTime.Now.Date);
if (bar.EndTime < endDate)
{
_spy.Add(bar);
}
}
for (var i = 1; i < _spy.Count; i++)
{
_spyPerformance.Add((double)((_spy[i].Close / _spy[i - 1].Close) - 1));
}
var aapl = Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
var aaplPath = LeanData.GenerateZipFilePath(Globals.DataFolder, aapl, new DateTime(2020, 3, 1), Resolution.Daily, TickType.Trade);
var aaplConfig = new QuantConnect.Data.SubscriptionDataConfig(typeof(TradeBar), aapl, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, false, false, false);
foreach (var line in QuantConnect.Compression.ReadLines(aaplPath))
{
var bar = TradeBar.ParseEquity(aaplConfig, line, DateTime.Now.Date);
if (bar.EndTime < endDate)
{
_aapl.Add(bar);
}
}
for (var i = 1; i < _aapl.Count; i++)
{
_aaplPerformance.Add((double)((_aapl[i].Close / _aapl[i - 1].Close) - 1));
}
}
[OneTimeTearDown]
public void Delete()
{
_spy.Clear();
_aapl.Clear();
_spyPerformance.Clear();
_aaplPerformance.Clear();
}
[Test]
public void OneYearPerformance()
{
var result = QuantConnect.Statistics.Statistics.TrackingError(_aaplPerformance.Take(252).ToList(), _spyPerformance.Take(252).ToList(), _algorithm.Settings.TradingDaysPerYear.Value);
Assert.AreEqual(0.52780899407691173, result);
}
[Test]
public void TotalPerformance()
{
// This might seem arbitrary, but there's 1 missing date vs. AAPL for SPY data, and it happens to be at line 5555 for date 2020-01-31
var result = QuantConnect.Statistics.Statistics.TrackingError(_aaplPerformance.Take(5555).ToList(), _spyPerformance.Take(5555).ToList(), _algorithm.Settings.TradingDaysPerYear.Value);
Assert.AreEqual(0.43074391577621751d, result, 0.00001);
}
[Test]
public void IdenticalPerformance()
{
var random = new Random();
var benchmarkPerformance = Enumerable.Repeat(random.NextDouble(), 252).ToList();
var algoPerformance = benchmarkPerformance.Select(element => element).ToList();
var result = QuantConnect.Statistics.Statistics.TrackingError(algoPerformance, benchmarkPerformance, _algorithm.Settings.TradingDaysPerYear.Value);
Assert.AreEqual(0.0, result);
}
[Test]
public void DifferentPerformance()
{
var benchmarkPerformance = new List<double>();
var algoPerformance = new List<double>();
// Gives us two sequences whose difference is always -175
// This sequence will have variance 0
var baseReturn = -176;
for (var i = 1; i <= 252; i++)
{
benchmarkPerformance.Add(baseReturn + 1);
algoPerformance.Add((baseReturn * 2) + 2);
}
var result = QuantConnect.Statistics.Statistics.TrackingError(algoPerformance, benchmarkPerformance, _algorithm.Settings.TradingDaysPerYear.Value);
Assert.AreEqual(0.0, result);
}
[Test]
public void AllZeros()
{
var benchmarkPerformance = Enumerable.Repeat(0.0, 252).ToList();
var algoPerformance = Enumerable.Repeat(0.0, 252).ToList();
var result = QuantConnect.Statistics.Statistics.TrackingError(algoPerformance, benchmarkPerformance, _algorithm.Settings.TradingDaysPerYear.Value);
Assert.AreEqual(0.0, result);
}
}
}