/*
* 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.Configuration;
using QuantConnect.Lean.Engine;
using QuantConnect.Packets;
using QuantConnect.Util;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace QuantConnect.Tests
{
///
/// Local/desktop implementation of messaging system for Lean Engine.
///
public class RegressionTestMessageHandler : QuantConnect.Messaging.Messaging
{
private static readonly bool _updateRegressionStatistics = Config.GetBool("regression-update-statistics", false);
private AlgorithmNodePacket _job;
private AlgorithmManager _algorithmManager;
///
/// Initialize the messaging system
///
public void SetAlgorithmManager(AlgorithmManager algorithmManager)
{
_algorithmManager = algorithmManager;
}
///
/// Set the messaging channel
///
public override void SetAuthentication(AlgorithmNodePacket job)
{
base.SetAuthentication(job);
_job = job;
}
///
/// Send a generic base packet without processing
///
public override void Send(Packet packet)
{
base.Send(packet);
switch (packet.Type)
{
case PacketType.BacktestResult:
var result = (BacktestResultPacket)packet;
if (result.Progress == 1)
{
if (_updateRegressionStatistics && _job.Language == Language.CSharp)
{
UpdateRegressionStatisticsInSourceFile(result.Results.Statistics, _algorithmManager, "../../../Algorithm.CSharp", $"{_job.AlgorithmId}.cs");
}
}
break;
default:
break;
}
}
public static void UpdateRegressionStatisticsInSourceFile(IDictionary statistics, AlgorithmManager algorithmManager, string folder, string fileToUpdate)
{
var algorithmSource = Directory.EnumerateFiles(folder, fileToUpdate, SearchOption.AllDirectories).Single();
var file = File.ReadAllLines(algorithmSource).ToList().GetEnumerator();
var lines = new List();
while (file.MoveNext())
{
var line = file.Current;
if (line == null)
{
continue;
}
if (line.Contains("Dictionary ExpectedStatistics => new Dictionary")
|| line.Contains("Dictionary ExpectedStatistics => new()"))
{
if (!statistics.Any() || line.EndsWith("();"))
{
lines.Add(line);
continue;
}
lines.Add(line);
lines.Add(" {");
foreach (var pair in statistics)
{
lines.Add($" {{\"{pair.Key}\", \"{pair.Value}\"}},");
}
// remove trailing comma
var lastLine = lines[lines.Count - 1];
lines[lines.Count - 1] = lastLine.Substring(0, lastLine.Length - 1);
// now we skip existing expected statistics in file
while (file.MoveNext())
{
line = file.Current;
if (line != null && line.Contains("};"))
{
lines.Add(line);
break;
}
}
}
else if (line.Contains($"long DataPoints =>"))
{
if (line.EndsWith("-1;"))
{
lines.Add(line);
}
else
{
lines.Add(GetDataPointLine(line, algorithmManager?.DataPoints.ToString()));
}
}
else if (line.Contains($"int AlgorithmHistoryDataPoints =>"))
{
if (line.EndsWith("-1;"))
{
lines.Add(line);
}
else
{
lines.Add(GetDataPointLine(line, algorithmManager?.AlgorithmHistoryDataPoints.ToString()));
}
}
else if (line.Contains($"AlgorithmStatus AlgorithmStatus =>"))
{
lines.Add(GetAlgorithmStatusLine(line, algorithmManager?.State.ToString()));
}
else
{
lines.Add(line);
}
}
file.DisposeSafely();
File.WriteAllLines(algorithmSource, lines);
}
private static string GetDataPointLine(string currentLine, string count)
{
var dataParts = currentLine.Split(" ");
dataParts[^1] = count + ";";
return string.Join(" ", dataParts);
}
private static string GetAlgorithmStatusLine(string currentLine, string algorithmStatus)
{
var dataParts = currentLine.Split(" ");
dataParts[^1] = "AlgorithmStatus." + algorithmStatus + ";";
return string.Join(" ", dataParts);
}
}
}