/* * 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.IO; using System.Web; using System.Linq; using NUnit.Framework; using QuantConnect.Api; using System.Collections.Generic; using QuantConnect.Optimizer.Parameters; using QuantConnect.Util; using QuantConnect.Optimizer; using QuantConnect.Optimizer.Objectives; using System.Threading; namespace QuantConnect.Tests.API { /// /// API Project endpoints, includes some Backtest endpoints testing as well /// [TestFixture, Explicit("Requires configured api access and available backtest node to run on"), Parallelizable(ParallelScope.Fixtures)] public class ProjectTests : ApiTestBase { private readonly Dictionary _defaultSettings = new Dictionary() { { "id", "QuantConnectBrokerage" }, { "environment", "paper" }, { "cash", new List>() { {new Dictionary { { "currency" , "USD"}, { "amount", 300000} } } } }, { "holdings", new List>() { {new Dictionary { { "symbolId" , Symbols.AAPL.ID.ToString()}, { "symbol", Symbols.AAPL.Value}, { "quantity", 1 }, { "averagePrice", 1} } } } }, }; [Test] public void ReadProject() { var readProject = ApiClient.ReadProject(TestProject.ProjectId); Assert.IsTrue(readProject.Success); Assert.AreEqual(1, readProject.Projects.Count); var project = readProject.Projects[0]; Assert.AreNotEqual(0, project.OwnerId); } /// /// Test creating and deleting projects with the Api /// [Test] public void Projects_CanBeCreatedAndDeleted_Successfully() { var name = $"TestProject{GetTimestamp()}"; //Test create a new project successfully var project = ApiClient.CreateProject(name, Language.CSharp, TestOrganization); var stringRepresentation = project.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(project.Success); Assert.Greater(project.Projects.First().ProjectId, 0); Assert.AreEqual(name, project.Projects.First().Name); // Delete the project var deleteProject = ApiClient.DeleteProject(project.Projects.First().ProjectId); Assert.IsTrue(deleteProject.Success); // Make sure the project is really deleted var projectList = ApiClient.ListProjects(); Assert.IsFalse(projectList.Projects.Any(p => p.ProjectId == project.Projects.First().ProjectId)); } /// /// Test updating the files associated with a project /// [Test] public void CRUD_ProjectFiles_Successfully() { var fakeFile = new ProjectFile { Name = "Hello.cs", Code = HttpUtility.HtmlEncode("Hello, world!") }; var realFile = new ProjectFile { Name = "main.cs", Code = HttpUtility.HtmlEncode(File.ReadAllText("../../../Algorithm.CSharp/BasicTemplateAlgorithm.cs")) }; var secondRealFile = new ProjectFile() { Name = "algorithm.cs", Code = HttpUtility.HtmlEncode(File.ReadAllText("../../../Algorithm.CSharp/BubbleAlgorithm.cs")) }; // Add random file var randomAdd = ApiClient.AddProjectFile(TestProject.ProjectId, fakeFile.Name, fakeFile.Code); var stringRepresentation = randomAdd.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(randomAdd.Success); // Update names of file var updatedName = ApiClient.UpdateProjectFileName(TestProject.ProjectId, fakeFile.Name, realFile.Name); Assert.IsTrue(updatedName.Success); // Replace content of file var updateContents = ApiClient.UpdateProjectFileContent(TestProject.ProjectId, realFile.Name, realFile.Code); Assert.IsTrue(updateContents.Success); // Read single file var readFile = ApiClient.ReadProjectFile(TestProject.ProjectId, realFile.Name); stringRepresentation = readFile.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(readFile.Success); Assert.IsTrue(readFile.Files.First().Code == realFile.Code); Assert.IsTrue(readFile.Files.First().Name == realFile.Name); // Add a second file var secondFile = ApiClient.AddProjectFile(TestProject.ProjectId, secondRealFile.Name, secondRealFile.Code); Assert.IsTrue(secondFile.Success); // Read multiple files var readFiles = ApiClient.ReadProjectFiles(TestProject.ProjectId); Assert.IsTrue(readFiles.Success); Assert.IsTrue(readFiles.Files.Count == 4); // 2 Added + 2 Automatic (Research.ipynb & Main.cs) // Delete the second file var deleteFile = ApiClient.DeleteProjectFile(TestProject.ProjectId, secondRealFile.Name); Assert.IsTrue(deleteFile.Success); // Read files var readFilesAgain = ApiClient.ReadProjectFiles(TestProject.ProjectId); Assert.IsTrue(readFilesAgain.Success); Assert.IsTrue(readFilesAgain.Files.Count == 3); Assert.IsTrue(readFilesAgain.Files.Any(x => x.Name == realFile.Name)); } /// /// Test updating the nodes associated with a project /// [Test] public void RU_ProjectNodes_Successfully() { // Read the nodes var nodesResponse = ApiClient.ReadProjectNodes(TestProject.ProjectId); var stringRepresentation = nodesResponse.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(nodesResponse.Success); Assert.Greater(nodesResponse.Nodes.BacktestNodes.Count, 0); // Save reference node var node = nodesResponse.Nodes.BacktestNodes.First(); var nodeId = node.Id; var active = node.Active; // If the node is active, deactivate it. Otherwise, set active to true var nodes = node.Active ? Array.Empty() : new[] { nodeId }; // Update the nodes nodesResponse = ApiClient.UpdateProjectNodes(TestProject.ProjectId, nodes); Assert.IsTrue(nodesResponse.Success); // Node has a new active state node = nodesResponse.Nodes.BacktestNodes.First(x => x.Id == nodeId); Assert.AreNotEqual(active, node.Active); // Set it back to previous state nodes = node.Active ? Array.Empty() : new[] { nodeId }; nodesResponse = ApiClient.UpdateProjectNodes(TestProject.ProjectId, nodes); Assert.IsTrue(nodesResponse.Success); // Node has a new active state node = nodesResponse.Nodes.BacktestNodes.First(x => x.Id == nodeId); Assert.AreEqual(active, node.Active); } /// /// Test creating, compiling and backtesting a C# project via the Api /// [Test] public void CSharpProject_CreatedCompiledAndBacktested_Successully() { var language = Language.CSharp; var code = File.ReadAllText("../../../Algorithm.CSharp/BasicTemplateAlgorithm.cs"); var algorithmName = "Main.cs"; var projectName = $"{GetTimestamp()} Test {TestAccount} Lang {language}"; Perform_CreateCompileBackTest_Tests(projectName, language, algorithmName, code); } /// /// Test creating, compiling and backtesting a Python project via the Api /// [Test] public void PythonProject_CreatedCompiledAndBacktested_Successully() { var language = Language.Python; var code = File.ReadAllText("../../../Algorithm.Python/BasicTemplateAlgorithm.py"); var algorithmName = "main.py"; var projectName = $"{GetTimestamp()} Test {TestAccount} Lang {language}"; Perform_CreateCompileBackTest_Tests(projectName, language, algorithmName, code); } private void Perform_CreateCompileBackTest_Tests(string projectName, Language language, string algorithmName, string code, string expectedStatus = "Completed.") { //Test create a new project successfully var project = ApiClient.CreateProject(projectName, language, TestOrganization); Assert.IsTrue(project.Success); Assert.Greater(project.Projects.First().ProjectId, 0); Assert.AreEqual(projectName, project.Projects.First().Name); // Make sure the project just created is now present var projects = ApiClient.ListProjects(); Assert.IsTrue(projects.Success); Assert.IsTrue(projects.Projects.Any(p => p.ProjectId == project.Projects.First().ProjectId)); // Test read back the project we just created var readProject = ApiClient.ReadProject(project.Projects.First().ProjectId); Assert.IsTrue(readProject.Success); Assert.AreEqual(projectName, readProject.Projects.First().Name); // Test change project file name and content var file = new ProjectFile { Name = algorithmName, Code = code }; var updateProjectFileContent = ApiClient.UpdateProjectFileContent(project.Projects.First().ProjectId, file.Name, file.Code); Assert.IsTrue(updateProjectFileContent.Success); // Download the project again to validate its got the new file var verifyRead = ApiClient.ReadProject(project.Projects.First().ProjectId); Assert.IsTrue(verifyRead.Success); // Compile the project we've created var compileCreate = ApiClient.CreateCompile(project.Projects.First().ProjectId); Assert.IsTrue(compileCreate.Success); Assert.AreEqual(CompileState.InQueue, compileCreate.State); // Read out the compile var compileSuccess = WaitForCompilerResponse(ApiClient, project.Projects.First().ProjectId, compileCreate.CompileId); Assert.IsTrue(compileSuccess.Success); Assert.AreEqual(CompileState.BuildSuccess, compileSuccess.State); // Update the file, create a build error, test we get build error file.Code += "[Jibberish at end of the file to cause a build error]"; ApiClient.UpdateProjectFileContent(project.Projects.First().ProjectId, file.Name, file.Code); var compileError = ApiClient.CreateCompile(project.Projects.First().ProjectId); compileError = WaitForCompilerResponse(ApiClient, project.Projects.First().ProjectId, compileError.CompileId); Assert.IsTrue(compileError.Success); // Successfully processed rest request. Assert.AreEqual(CompileState.BuildError, compileError.State); //Resulting in build fail. // Using our successful compile; launch a backtest! var backtestName = $"{DateTime.UtcNow.ToStringInvariant("u")} API Backtest"; var backtest = ApiClient.CreateBacktest(project.Projects.First().ProjectId, compileSuccess.CompileId, backtestName); Assert.IsTrue(backtest.Success); // Now read the backtest and wait for it to complete var backtestRead = WaitForBacktestCompletion(ApiClient, project.Projects.First().ProjectId, backtest.BacktestId, secondsTimeout: 600, returnFailedBacktest: true); Assert.IsTrue(backtestRead.Success); Assert.AreEqual(expectedStatus, backtestRead.Status); if (expectedStatus == "Runtime Error") { Assert.IsTrue(backtestRead.Error.Contains("Intentional Failure", StringComparison.InvariantCulture) || backtestRead.HasInitializeError); } else { Assert.AreEqual(1, backtestRead.Progress); Assert.AreEqual(backtestName, backtestRead.Name); Assert.AreEqual("1", backtestRead.Statistics["Total Orders"]); Assert.Greater(backtestRead.Charts["Benchmark"].Series.Count, 0); // In the same way, read the orders returned in the backtest var backtestOrdersRead = ApiClient.ReadBacktestOrders(project.Projects.First().ProjectId, backtest.BacktestId, 0, 1); Assert.IsTrue(backtestOrdersRead.Any()); Assert.AreEqual(Symbols.SPY.Value, backtestOrdersRead.First().Symbol.Value); // Verify we have the backtest in our project var listBacktests = ApiClient.ListBacktests(project.Projects.First().ProjectId); Assert.IsTrue(listBacktests.Success); Assert.GreaterOrEqual(listBacktests.Backtests.Count, 1); Assert.AreEqual(backtestName, listBacktests.Backtests[0].Name); // Update the backtest name and test its been updated backtestName += "-Amendment"; var renameBacktest = ApiClient.UpdateBacktest(project.Projects.First().ProjectId, backtest.BacktestId, backtestName); Assert.IsTrue(renameBacktest.Success); backtestRead = ApiClient.ReadBacktest(project.Projects.First().ProjectId, backtest.BacktestId); Assert.AreEqual(backtestName, backtestRead.Name); //Update the note and make sure its been updated: var newNote = DateTime.Now.ToStringInvariant("u"); var noteBacktest = ApiClient.UpdateBacktest(project.Projects.First().ProjectId, backtest.BacktestId, note: newNote); Assert.IsTrue(noteBacktest.Success); backtestRead = ApiClient.ReadBacktest(project.Projects.First().ProjectId, backtest.BacktestId); Assert.AreEqual(newNote, backtestRead.Note); } // Delete the backtest we just created var deleteBacktest = ApiClient.DeleteBacktest(project.Projects.First().ProjectId, backtest.BacktestId); Assert.IsTrue(deleteBacktest.Success); // Test delete the project we just created var deleteProject = ApiClient.DeleteProject(project.Projects.First().ProjectId); Assert.IsTrue(deleteProject.Success); } [Test] public void ReadBacktestOrdersReportAndChart() { // Project settings var language = Language.CSharp; var code = File.ReadAllText("../../../Algorithm.CSharp/BasicTemplateAlgorithm.cs"); var algorithmName = "Main.cs"; var projectName = $"{GetTimestamp()} Test {TestAccount} Lang {language}"; // Create a default project var projectResult = ApiClient.CreateProject(projectName, language, TestOrganization); Assert.IsTrue(projectResult.Success, $"Error creating project:\n {string.Join("\n ", projectResult.Errors)}"); var project = projectResult.Projects.First(); var file = new ProjectFile { Name = algorithmName, Code = code }; var updateProjectFileContent = ApiClient.UpdateProjectFileContent(project.ProjectId, file.Name, file.Code); Assert.IsTrue(updateProjectFileContent.Success, $"Error updating project file:\n {string.Join("\n ", updateProjectFileContent.Errors)}"); var compileCreate = ApiClient.CreateCompile(project.ProjectId); var compileSuccess = WaitForCompilerResponse(ApiClient, project.ProjectId, compileCreate.CompileId); Assert.IsTrue(compileSuccess.Success, $"Error compiling project:\n {string.Join("\n ", compileSuccess.Errors)}"); var backtestName = $"ReadBacktestOrders Backtest {GetTimestamp()}"; var backtest = ApiClient.CreateBacktest(project.ProjectId, compileSuccess.CompileId, backtestName); // Read ongoing backtest var backtestRead = ApiClient.ReadBacktest(project.ProjectId, backtest.BacktestId); Assert.IsTrue(backtestRead.Success); // Now wait until the backtest is completed and request the orders again backtestRead = WaitForBacktestCompletion(ApiClient, project.ProjectId, backtest.BacktestId); var backtestOrdersRead = ApiClient.ReadBacktestOrders(project.ProjectId, backtest.BacktestId); string stringRepresentation; foreach(var backtestOrder in backtestOrdersRead) { stringRepresentation = backtestOrder.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); } Assert.IsTrue(backtestOrdersRead.Any()); Assert.AreEqual(Symbols.SPY.Value, backtestOrdersRead.First().Symbol.Value); var readBacktestReport = ApiClient.ReadBacktestReport(project.ProjectId, backtest.BacktestId); stringRepresentation = readBacktestReport.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(readBacktestReport.Success); Assert.IsFalse(string.IsNullOrEmpty(readBacktestReport.Report)); var readBacktestChart = ApiClient.ReadBacktestChart( project.ProjectId, "Strategy Equity", new DateTime(2013, 10, 07).Second, new DateTime(2013, 10, 11).Second, 1000, backtest.BacktestId); stringRepresentation = readBacktestChart.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(readBacktestChart.Success); Assert.IsNotNull(readBacktestChart.Chart); // Delete the backtest we just created var deleteBacktest = ApiClient.DeleteBacktest(project.ProjectId, backtest.BacktestId); Assert.IsTrue(deleteBacktest.Success); // Delete the project we just created var deleteProject = ApiClient.DeleteProject(project.ProjectId); Assert.IsTrue(deleteProject.Success); } [Test] public void UpdateBacktestName() { // We will be using the existing TestBacktest for this test var originalName = TestBacktest.Name; var newName = $"{originalName} - Amended - {DateTime.UtcNow.ToStringInvariant("u")}"; // Update the backtest name var updateResult = ApiClient.UpdateBacktest(TestProject.ProjectId, TestBacktest.BacktestId, name: newName); Assert.IsTrue(updateResult.Success, $"Error updating backtest name:\n {string.Join("\n ", updateResult.Errors)}"); // Read the backtest and verify the name has been updated var readResult = ApiClient.ReadBacktest(TestProject.ProjectId, TestBacktest.BacktestId); Assert.IsTrue(readResult.Success, $"Error reading backtest:\n {string.Join("\n ", readResult.Errors)}"); Assert.AreEqual(newName, readResult.Name); // Revert the name back to the original updateResult = ApiClient.UpdateBacktest(TestProject.ProjectId, TestBacktest.BacktestId, name: originalName); Assert.IsTrue(updateResult.Success, $"Error updating backtest name:\n {string.Join("\n ", updateResult.Errors)}"); // Read the backtest and verify the name has been updated readResult = ApiClient.ReadBacktest(TestProject.ProjectId, TestBacktest.BacktestId); Assert.IsTrue(readResult.Success, $"Error reading backtest:\n {string.Join("\n ", readResult.Errors)}"); Assert.AreEqual(originalName, readResult.Name); } [Test] public void ReadLiveInsightsWorksAsExpected() { var quantConnectDataProvider = new Dictionary { { "id", "QuantConnectBrokerage" }, }; var dataProviders = new Dictionary { { "QuantConnectBrokerage", quantConnectDataProvider } }; GetProjectAndCompileIdToReadInsights(out var projectId, out var compileId); // Get a live node to launch the algorithm on var nodesResponse = ApiClient.ReadProjectNodes(projectId); Assert.IsTrue(nodesResponse.Success); var freeNode = nodesResponse.Nodes.LiveNodes.Where(x => x.Busy == false); Assert.IsNotEmpty(freeNode, "No free Live Nodes found"); try { // Create live default algorithm var createLiveAlgorithm = ApiClient.CreateLiveAlgorithm(projectId, compileId, freeNode.FirstOrDefault().Id, _defaultSettings, dataProviders: dataProviders); Assert.IsTrue(createLiveAlgorithm.Success, $"ApiClient.CreateLiveAlgorithm(): Error: {string.Join(",", createLiveAlgorithm.Errors)}"); // Wait 2 minutes Thread.Sleep(120000); // Stop the algorithm var stopLive = ApiClient.StopLiveAlgorithm(projectId); Assert.IsTrue(stopLive.Success, $"ApiClient.StopLiveAlgorithm(): Error: {string.Join(",", stopLive.Errors)}"); // Try to read the insights from the algorithm var readInsights = ApiClient.ReadLiveInsights(projectId, 0, 5); var finish = DateTime.UtcNow.AddMinutes(2); do { Thread.Sleep(5000); readInsights = ApiClient.ReadLiveInsights(projectId, 0, 5); } while (finish > DateTime.UtcNow && !readInsights.Insights.Any()); Assert.IsTrue(readInsights.Success, $"ApiClient.ReadLiveInsights(): Error: {string.Join(",", readInsights.Errors)}"); Assert.IsNotEmpty(readInsights.Insights); Assert.IsTrue(readInsights.Length >= 0); Assert.Throws(() => ApiClient.ReadLiveInsights(projectId, 0, 101)); Assert.DoesNotThrow(() => ApiClient.ReadLiveInsights(projectId)); } catch (Exception ex) { // Delete the project in case of an error Assert.IsTrue(ApiClient.DeleteProject(projectId).Success); throw ex; } // Delete the project var deleteProject = ApiClient.DeleteProject(projectId); Assert.IsTrue(deleteProject.Success); } [Test] public void UpdatesBacktestTags() { // We will be using the existing TestBacktest for this test var tags = new List { "tag1", "tag2", "tag3" }; // Add the tags to the backtest var addTagsResult = ApiClient.UpdateBacktestTags(TestProject.ProjectId, TestBacktest.BacktestId, tags); Assert.IsTrue(addTagsResult.Success, $"Error adding tags to backtest:\n {string.Join("\n ", addTagsResult.Errors)}"); // Read the backtest and verify the tags were added var backtestsResult = ApiClient.ListBacktests(TestProject.ProjectId); var stringRepresentation = backtestsResult.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(backtestsResult.Success, $"Error getting backtests:\n {string.Join("\n ", backtestsResult.Errors)}"); Assert.AreEqual(1, backtestsResult.Backtests.Count); CollectionAssert.AreEquivalent(tags, backtestsResult.Backtests[0].Tags); // Remove all tags from the backtest var deleteTagsResult = ApiClient.UpdateBacktestTags(TestProject.ProjectId, TestBacktest.BacktestId, new List()); Assert.IsTrue(deleteTagsResult.Success, $"Error deleting tags from backtest:\n {string.Join("\n ", deleteTagsResult.Errors)}"); // Read the backtest and verify the tags were deleted backtestsResult = ApiClient.ListBacktests(TestProject.ProjectId); Assert.IsTrue(backtestsResult.Success, $"Error getting backtests:\n {string.Join("\n ", backtestsResult.Errors)}"); Assert.AreEqual(1, backtestsResult.Backtests.Count); Assert.AreEqual(0, backtestsResult.Backtests[0].Tags.Count); } [Test] public void ReadBacktestInsightsWorksAsExpected() { GetProjectAndCompileIdToReadInsights(out var projectId, out var compileId); try { // Create backtest var backtestName = $"ReadBacktestOrders Backtest {GetTimestamp()}"; var backtest = ApiClient.CreateBacktest(projectId, compileId, backtestName); var stringRepresentation = backtest.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); // Try to read the insights from the algorithm var readInsights = ApiClient.ReadBacktestInsights(projectId, backtest.BacktestId, 0, 5); stringRepresentation = readInsights.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); var finish = DateTime.UtcNow.AddMinutes(2); do { Thread.Sleep(1000); readInsights = ApiClient.ReadBacktestInsights(projectId, backtest.BacktestId, 0, 5); } while (finish > DateTime.UtcNow && !readInsights.Insights.Any()); Assert.IsTrue(readInsights.Success, $"ApiClient.ReadBacktestInsights(): Error: {string.Join(",", readInsights.Errors)}"); Assert.IsNotEmpty(readInsights.Insights); Assert.IsTrue(readInsights.Length >= 0); Assert.Throws(() => ApiClient.ReadBacktestInsights(projectId, backtest.BacktestId, 0, 101)); Assert.DoesNotThrow(() => ApiClient.ReadBacktestInsights(projectId, backtest.BacktestId)); } catch (Exception ex) { // Delete the project in case of an error Assert.IsTrue(ApiClient.DeleteProject(projectId).Success); throw ex; } // Delete the project var deleteProject = ApiClient.DeleteProject(projectId); Assert.IsTrue(deleteProject.Success); } [Test] public void CreatesLiveAlgorithm() { var quantConnectDataProvider = new Dictionary { { "id", "QuantConnectBrokerage" }, }; var dataProviders = new Dictionary { { "QuantConnectBrokerage", quantConnectDataProvider } }; var file = new ProjectFile { Name = "Main.cs", Code = File.ReadAllText("../../../Algorithm.CSharp/BasicTemplateAlgorithm.cs") }; // Create a new project var project = ApiClient.CreateProject($"Test project - {DateTime.Now.ToStringInvariant()}", Language.CSharp, TestOrganization); var projectId = project.Projects.First().ProjectId; // Update Project Files var updateProjectFileContent = ApiClient.UpdateProjectFileContent(projectId, "Main.cs", file.Code); Assert.IsTrue(updateProjectFileContent.Success); // Create compile var compile = ApiClient.CreateCompile(projectId); var stringRepresentation = compile.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(compile.Success); // Wait at max 30 seconds for project to compile var compileCheck = WaitForCompilerResponse(ApiClient, projectId, compile.CompileId); Assert.IsTrue(compileCheck.Success); Assert.IsTrue(compileCheck.State == CompileState.BuildSuccess); // Get a live node to launch the algorithm on var nodesResponse = ApiClient.ReadProjectNodes(projectId); Assert.IsTrue(nodesResponse.Success); var freeNode = nodesResponse.Nodes.LiveNodes.Where(x => x.Busy == false); Assert.IsNotEmpty(freeNode, "No free Live Nodes found"); try { // Create live default algorithm var createLiveAlgorithm = ApiClient.CreateLiveAlgorithm(projectId, compile.CompileId, freeNode.FirstOrDefault().Id, _defaultSettings, dataProviders: dataProviders); stringRepresentation = createLiveAlgorithm.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(createLiveAlgorithm.Success, $"ApiClient.CreateLiveAlgorithm(): Error: {string.Join(",", createLiveAlgorithm.Errors)}"); // Read live algorithm var readLiveAlgorithm = ApiClient.ReadLiveAlgorithm(projectId, createLiveAlgorithm.DeployId); stringRepresentation = readLiveAlgorithm.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(readLiveAlgorithm.Success, $"ApiClient.ReadLiveAlgorithm(): Error: {string.Join(",", readLiveAlgorithm.Errors)}"); // Stop the algorithm var stopLive = ApiClient.StopLiveAlgorithm(projectId); Assert.IsTrue(stopLive.Success, $"ApiClient.StopLiveAlgorithm(): Error: {string.Join(",", stopLive.Errors)}"); var readChart = ApiClient.ReadLiveChart(projectId, "Strategy Equity", new DateTime(2013, 10, 07).Second, new DateTime(2013, 10, 11).Second, 1000); Assert.IsTrue(readChart.Success, $"ApiClient.ReadLiveChart(): Error: {string.Join(",", readChart.Errors)}"); Assert.IsNotNull(readChart.Chart); var readLivePortfolio = ApiClient.ReadLivePortfolio(projectId); stringRepresentation = readLivePortfolio.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(readLivePortfolio.Success, $"ApiClient.ReadLivePortfolio(): Error: {string.Join(",", readLivePortfolio.Errors)}"); Assert.IsNotNull(readLivePortfolio.Portfolio, "Portfolio was null!"); Assert.IsNotNull(readLivePortfolio.Portfolio.Cash, "Portfolio.Cash was null!"); Assert.IsNotNull(readLivePortfolio.Portfolio.Holdings, "Portfolio Holdings was null!"); var readLiveLogs = ApiClient.ReadLiveLogs(projectId, createLiveAlgorithm.DeployId, 0, 20); Assert.IsTrue(readLiveLogs.Success, $"ApiClient.ReadLiveLogs(): Error: {string.Join(",", readLiveLogs.Errors)}"); Assert.IsNotNull(readLiveLogs.Logs, "Logs was null!"); Assert.IsTrue(readLiveLogs.Length >= 0, "The length of the logs was negative!"); Assert.IsTrue(readLiveLogs.DeploymentOffset >= 0, "The deploymentOffset"); } catch(Exception ex) { // Delete the project in case of an error Assert.IsTrue(ApiClient.DeleteProject(projectId).Success); throw ex; } // Delete the project var deleteProject = ApiClient.DeleteProject(projectId); Assert.IsTrue(deleteProject.Success); } [Test] public void ReadVersionsWorksAsExpected() { var result = ApiClient.ReadLeanVersions(); var stringRepresentation = result.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsTrue(result.Success); Assert.IsNotEmpty(result.Versions); } [Test] public void CreatesOptimization() { var file = new ProjectFile { Name = "Main.cs", Code = File.ReadAllText("../../../Algorithm.CSharp/ParameterizedAlgorithm.cs") }; // Create a new project var project = ApiClient.CreateProject($"Test project optimization - {DateTime.Now.ToStringInvariant()}", Language.CSharp, TestOrganization); var projectId = project.Projects.First().ProjectId; // Update Project Files var updateProjectFileContent = ApiClient.UpdateProjectFileContent(projectId, "Main.cs", file.Code); Assert.IsTrue(updateProjectFileContent.Success); // Create compile var compile = ApiClient.CreateCompile(projectId); Assert.IsTrue(compile.Success); // Wait at max 30 seconds for project to compile var compileCheck = WaitForCompilerResponse(ApiClient, projectId, compile.CompileId); Assert.IsTrue(compileCheck.Success); Assert.IsTrue(compileCheck.State == CompileState.BuildSuccess); var backtestName = $"Estimate optimization Backtest"; var backtest = ApiClient.CreateBacktest(projectId, compile.CompileId, backtestName); // Now wait until the backtest is completed and request the orders again var backtestReady = WaitForBacktestCompletion(ApiClient, projectId, backtest.BacktestId); Assert.IsTrue(backtestReady.Success); var optimization = ApiClient.CreateOptimization( projectId: projectId, name: "My Testable Optimization", target: "TotalPerformance.PortfolioStatistics.SharpeRatio", targetTo: "max", targetValue: null, strategy: "QuantConnect.Optimizer.Strategies.GridSearchOptimizationStrategy", compileId: compile.CompileId, parameters: new HashSet { new OptimizationStepParameter("ema-fast", 50, 150, 1, 1) // Replace params with valid optimization parameter data for test project }, constraints: new List { new Constraint("TotalPerformance.PortfolioStatistics.SharpeRatio", ComparisonOperatorTypes.GreaterOrEqual, 1) }, estimatedCost: 0.06m, nodeType: OptimizationNodes.O2_8, parallelNodes: 12 ); var stringRepresentation = optimization.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); var finish = DateTime.UtcNow.AddMinutes(5); var readOptimization = ApiClient.ReadOptimization(optimization.OptimizationId); do { Thread.Sleep(5000); readOptimization = ApiClient.ReadOptimization(optimization.OptimizationId); } while (finish > DateTime.UtcNow && readOptimization.Status != OptimizationStatus.Completed); stringRepresentation = readOptimization.ToString(); Assert.IsTrue(ApiTestBase.IsValidJson(stringRepresentation)); Assert.IsNotNull(optimization); Assert.IsNotEmpty(optimization.OptimizationId); Assert.AreNotEqual(default(DateTime), optimization.Created); Assert.Positive(optimization.ProjectId); Assert.IsNotEmpty(optimization.Name); Assert.IsInstanceOf(optimization.Status); Assert.IsNotEmpty(optimization.NodeType); Assert.IsTrue(0 <= optimization.OutOfSampleDays); Assert.AreNotEqual(default(DateTime), optimization.OutOfSampleMaxEndDate); Assert.IsNotNull(optimization.Criterion); // Delete the project var deleteProject = ApiClient.DeleteProject(projectId); Assert.IsTrue(deleteProject.Success); } private static string GetTimestamp() { return DateTime.UtcNow.ToStringInvariant("yyyyMMddHHmmssfffff"); } private void GetProjectAndCompileIdToReadInsights(out int projectId, out string compileId) { var file = new ProjectFile { Name = "Main.cs", Code = File.ReadAllText("../../../Algorithm.CSharp/BasicTemplateCryptoFrameworkAlgorithm.cs") }; // Create a new project var project = ApiClient.CreateProject($"Test project insight - {DateTime.Now.ToStringInvariant()}", Language.CSharp, TestOrganization); projectId = project.Projects.First().ProjectId; // Update Project Files var updateProjectFileContent = ApiClient.UpdateProjectFileContent(projectId, "Main.cs", file.Code); Assert.IsTrue(updateProjectFileContent.Success); // Create compile var compile = ApiClient.CreateCompile(projectId); Assert.IsTrue(compile.Success); compileId = compile.CompileId; // Wait at max 30 seconds for project to compile var compileCheck = WaitForCompilerResponse(ApiClient, projectId, compile.CompileId); Assert.IsTrue(compileCheck.Success); Assert.IsTrue(compileCheck.State == CompileState.BuildSuccess); } /// /// Test creating, compiling and backtesting a failure C# project via the Api /// [TestCase("Constructor")] [TestCase("Initialize")] [TestCase("OnData")] public void CSharpProject_CreatedCompiledAndBacktested_Unsuccessully(string section) { var language = Language.CSharp; var code = File.ReadAllText("../../../Algorithm.CSharp/BasicTemplateAlgorithm.cs"); if (section == "Constructor") { code = code.Replace("private Symbol _spy = QuantConnect.Symbol.Create(\"SPY\", SecurityType.Equity, Market.USA);", "private Symbol _spy = QuantConnect.Symbol.Create(\"SPY\", SecurityType.Equity, Market.USA);" + "public BasicTemplateAlgorithm(): base() { throw new RegressionTestException(\"Intentional Failure\"); }", StringComparison.InvariantCulture); } else if (section == "Initialize") { code = code.Replace("SetStartDate(2013, 10, 07);", "throw new RegressionTestException($\"Intentional Failure\");", StringComparison.InvariantCulture); } else if (section == "OnData") { code = code.Replace("Debug(\"Purchased Stock\");", "throw new RegressionTestException($\"Intentional Failure\");", StringComparison.InvariantCulture); } var algorithmName = "Main.cs"; var projectName = $"{GetTimestamp()} Test {TestAccount} Lang {language}"; Perform_CreateCompileBackTest_Tests(projectName, language, algorithmName, code, "Runtime Error"); } /// /// Test creating, compiling and backtesting a failure Python project via the Api /// [TestCase("Constructor")] [TestCase("Initialize")] [TestCase("OnData")] public void PythonProject_CreatedCompiledAndBacktested_Unsuccessully(string section) { var language = Language.Python; var code = File.ReadAllText("../../../Algorithm.Python/BasicTemplateAlgorithm.py"); if (section == "Constructor") { code = code.Replace("self.set_start_date(2013,10, 7) #Set Start Date", "self.set_start_date(2013,10, 7) #Set Start Date\n" + " def __init__(self):\r\n super().__init__()\r\n raise Exception(\"Intentional Failure\")", StringComparison.InvariantCulture); } else if (section == "Initialize") { code = code.Replace("self.set_start_date(2013,10, 7) #Set Start Date", "raise Exception(\"Intentional Failure\")", StringComparison.InvariantCulture); } else if (section == "OnData") { code = code.Replace("self.set_holdings(\"SPY\", 1)", "self.set_holdings(\"SPY\", 1)\r\n" + " raise Exception(\"Intentional Failure\")", StringComparison.InvariantCulture); } var algorithmName = "main.py"; var projectName = $"{GetTimestamp()} Test {TestAccount} Lang {language}"; Perform_CreateCompileBackTest_Tests(projectName, language, algorithmName, code, "Runtime Error"); } } }