Files
quantconnect--lean/VisualStudioPlugin/ToolWindow1Control.xaml.cs
2019-07-11 13:45:04 -03:00

414 lines
18 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.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
namespace QuantConnect.VisualStudioPlugin
{
using System.Linq;
using System.Windows.Controls;
using System;
using System.Windows;
using Microsoft.VisualStudio.Shell;
/// <summary>
/// Interaction logic for ToolWindow1Control.
/// </summary>
internal partial class ToolWindow1Control : UserControl, IBacktestObserver
{
private readonly ObservableCollection<DataGridItem> _dataGridCollection;
private readonly AuthenticationCommand _authenticationCommand;
// Limit to the amount of backtest to add to the table
private const int _maximumBacktestToShow = 50;
/// <summary>
/// Initializes a new instance of the <see cref="ToolWindow1Control"/> class.
/// </summary>
public ToolWindow1Control()
{
_dataGridCollection = new ObservableCollection<DataGridItem>();
InitializeComponent();
dataGrid.ItemsSource = _dataGridCollection;
_authenticationCommand = new AuthenticationCommand();
// sending false to avoid blocking UI when VS is starting and toolwindow is open
UpdateAvailableProjects(false);
}
/// <summary>
/// Callback for project combo box. Updates available backtest for the selected project.
/// </summary>
private void ProjectNameBox_SelectionChanged(object sender, RoutedEventArgs e)
{
var selectedItem = projectNameBox.SelectedItem as ComboboxProjectItem;
if (selectedItem != null)
{
var projectId = selectedItem.Id;
UpdateAvailableBacktests(projectId);
}
}
/// <summary>
/// Updates available backtests in the backtest data grid for a specific project
/// </summary>
/// <param name="projectId">Target project id</param>
private async void UpdateAvailableBacktests(int projectId)
{
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Loading project backtests...");
if (await _authenticationCommand.Login(ServiceProvider.GlobalProvider, false))
{
try
{
var backtestsList = await System.Threading.Tasks.Task.Run(() =>
{
var api = AuthorizationManager.GetInstance().GetApi();
var result = api.ListBacktests(projectId);
return result.Backtests;
});
var selectedItem = projectNameBox.SelectedItem as ComboboxProjectItem;
// Verify the backtest are from the selected project
if (selectedItem?.Id == projectId)
{
lock (_dataGridCollection)
{
_dataGridCollection.Clear();
// Setting a limit of _maximumBacktestToShow backtests in the table...
for (var i = 0; i < backtestsList.Count && i < _maximumBacktestToShow; i++)
{
_dataGridCollection.Add(new DataGridItem
{
Name = backtestsList[i].Name,
Progress = backtestsList[i].Progress,
ProjectId = projectId,
Date = backtestsList[i].Created,
BacktestId = backtestsList[i].BacktestId,
Status = string.IsNullOrEmpty(backtestsList[i].Error) ?
DataGridItem.BacktestSucceeded : DataGridItem.BacktestFailed,
Note = backtestsList[i].Note
});
}
}
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Successfully loaded backtests");
}
}
catch (Exception exception)
{
VsUtils.ShowErrorMessageBox(ServiceProvider.GlobalProvider,
"QuantConnect Exception", exception.ToString());
}
}
}
/// <summary>
/// Updates available projects in the combo box
/// </summary>
public async void UpdateAvailableProjects(bool showLoginDialog = true)
{
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Loading available projects...");
if (await _authenticationCommand.Login(ServiceProvider.GlobalProvider, false, showLoginDialog))
{
try
{
var projectNames = await System.Threading.Tasks.Task.Run(() =>
{
var api = AuthorizationManager.GetInstance().GetApi();
var projects = api.ListProjects().Projects;
return projects.Select(p => Tuple.Create(p.ProjectId, p.Name, p.Language)).ToList();
});
// Clear available projects
projectNameBox.Items.Clear();
lock (_dataGridCollection)
{
// Clear rows in the backtest data grid
_dataGridCollection.Clear();
}
if (projectNames.Count > 0)
{
projectNames.ForEach(p => projectNameBox.Items.Add(new ComboboxProjectItem(p.Item1, p.Item2, p.Item3)));
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Successfully loaded projects");
// Select first project and load available backtest
var project = projectNameBox.Items[0] as ComboboxProjectItem;
projectNameBox.SelectedItem = project;
}
else
{
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "No projects available");
}
}
catch (Exception exception)
{
VsUtils.ShowErrorMessageBox(ServiceProvider.GlobalProvider,
"QuantConnect Exception", exception.ToString());
}
}
}
/// <summary>
/// Callback for the open button in the backtest data grid, shared by all rows. Opens backtest.
/// </summary>
private void Open_OnClick(object sender, RoutedEventArgs e)
{
var obj = ((FrameworkElement)sender).DataContext as DataGridItem;
if (obj != null)
{
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Opening backtest");
var projectUrl = string.Format(
CultureInfo.CurrentCulture,
"https://www.quantconnect.com/terminal/#open/{0}/{1}",
obj.ProjectId,
obj.BacktestId
);
Process.Start(projectUrl);
}
}
/// <summary>
/// Callback for the delete button in the backtest data grid, shared by all rows. Deletes backtest.
/// </summary>
private async void Delete_OnClick(object sender, RoutedEventArgs e)
{
var obj = ((FrameworkElement)sender).DataContext as DataGridItem;
if (obj != null)
{
var projectId = obj.ProjectId;
var backtestId = obj.BacktestId;
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Deleting backtest...");
var deleteResult = false;
if (await _authenticationCommand.Login(ServiceProvider.GlobalProvider, false))
{
try
{
deleteResult = await System.Threading.Tasks.Task.Run(() =>
{
var api = AuthorizationManager.GetInstance().GetApi();
return api.DeleteBacktest(projectId, backtestId).Success;
});
}
catch (Exception exception)
{
VsUtils.ShowErrorMessageBox(ServiceProvider.GlobalProvider,
"QuantConnect Exception", exception.ToString());
}
}
if (deleteResult)
{
var selectedItem = projectNameBox.SelectedItem as ComboboxProjectItem;
// Verify the backtest is from the selected project
if (selectedItem?.Id == projectId)
{
lock (_dataGridCollection)
{
foreach (DataGridItem item in _dataGridCollection)
{
if (item.BacktestId == backtestId)
{
_dataGridCollection.Remove(item);
break;
}
}
}
}
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Successfully deleted backtest");
}
else
{
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Error when deleting backtest");
}
}
}
/// <summary>
/// Creates new backtest, row, in the backtest data grid (UI)
/// </summary>
/// <param name="projectId">Target project id</param>
/// <param name="backtestStatus">Backtest current status</param>
public void BacktestCreated(int projectId, Api.Backtest backtestStatus)
{
var selectedItem = projectNameBox.SelectedItem as ComboboxProjectItem;
// Verify the backtest is from the selected project
if (selectedItem?.Id == projectId)
{
lock (_dataGridCollection)
{
_dataGridCollection.Insert(0, new DataGridItem
{
Name = backtestStatus.Name,
Progress = 0,
ProjectId = projectId,
BacktestId = backtestStatus.BacktestId,
Date = backtestStatus.Created,
Status = DataGridItem.BacktestInProgress
});
}
}
}
/// <summary>
/// Updates backtest Progress in the backtest data grid (UI)
/// </summary>
/// <param name="projectId">Target project id</param>
/// <param name="backtestStatus">Backtest current status</param>
public void BacktestStatusUpdated(int projectId, Api.Backtest backtestStatus)
{
var selectedItem = projectNameBox.SelectedItem as ComboboxProjectItem;
// Verify the backtest is from the selected project
if (selectedItem?.Id == projectId)
{
lock (_dataGridCollection)
{
foreach (DataGridItem item in _dataGridCollection)
{
if (item.BacktestId == backtestStatus.BacktestId)
{
item.Progress = backtestStatus.Progress;
break;
}
}
}
}
}
/// <summary>
/// Updates backtest Status and Progress in the backtest data grid (UI)
/// </summary>
/// <param name="projectId">Target project id</param>
/// <param name="backtestStatus">Backtest current status</param>
public void BacktestFinished(int projectId, Api.Backtest backtestStatus)
{
var selectedItem = projectNameBox.SelectedItem as ComboboxProjectItem;
// Verify the backtest is from the selected project
if (selectedItem?.Id == projectId)
{
lock (_dataGridCollection)
{
foreach (DataGridItem item in _dataGridCollection)
{
if (item.BacktestId == backtestStatus.BacktestId)
{
var success = string.IsNullOrEmpty(backtestStatus.Error) &&
string.IsNullOrEmpty(backtestStatus.StackTrace);
item.Status = success ? DataGridItem.BacktestSucceeded : DataGridItem.BacktestFailed;
item.Progress = backtestStatus.Progress;
break;
}
}
}
}
}
/// <summary>
/// Callback for the refresh button. Will reload available projects and empty backtest data grid
/// </summary>
private void RefreshButton_OnClick(object sender, RoutedEventArgs e)
{
UpdateAvailableProjects();
}
/// <summary>
/// Callback for the new project button. Will show a new popup so the user can select name and language
/// Will create project calling the server through API.
/// </summary>
private async void NewProjectButton_OnClick(object sender, RoutedEventArgs e)
{
var window = new NewProjectDialog();
VsUtils.DisplayDialogWindow(window);
if (window.CreateNewProject &&
await _authenticationCommand.Login(ServiceProvider.GlobalProvider, false))
{
var result = false;
var projectId = 0;
try
{
var apiResponse = await System.Threading.Tasks.Task.Run(() =>
{
var api = AuthorizationManager.GetInstance().GetApi();
return api.CreateProject(window.NewProjectName, window.NewProjectLanguage);
});
if (apiResponse.Success && apiResponse.Projects.Count > 0)
{
result = true;
projectId = apiResponse.Projects.First().ProjectId;
}
}
catch (Exception exception)
{
VsUtils.ShowErrorMessageBox(ServiceProvider.GlobalProvider,
"QuantConnect Exception", exception.ToString());
}
if (result)
{
// lets update the combo box without having to go to the server again
var newProject = new ComboboxProjectItem(projectId, window.NewProjectName, window.NewProjectLanguage);
projectNameBox.Items.Add(newProject);
projectNameBox.SelectedItem = newProject;
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Successfully created a new project");
}
else
{
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Failed to create a new project");
}
}
}
/// <summary>
/// Callback for the edit button. Will show a new popup so the user can edit backtest name and note.
/// Will update the server through API.
/// </summary>
private async void Edit_OnClick(object sender, RoutedEventArgs e)
{
var obj = ((FrameworkElement)sender).DataContext as DataGridItem;
if (obj != null)
{
var projectId = obj.ProjectId;
var backtestId = obj.BacktestId;
var backtestNote = obj.Note;
var window = new EditBacktestDialog(obj.Name, backtestNote);
VsUtils.DisplayDialogWindow(window);
if (window.BacktestNameProvided &&
!string.IsNullOrEmpty(window.BacktestName) &&
await _authenticationCommand.Login(ServiceProvider.GlobalProvider, false))
{
var result = false;
try
{
result = await System.Threading.Tasks.Task.Run(() =>
{
var api = AuthorizationManager.GetInstance().GetApi();
return api.UpdateBacktest(projectId, backtestId, window.BacktestName, window.BacktestNote).Success;
});
}
catch (Exception exception)
{
VsUtils.ShowErrorMessageBox(ServiceProvider.GlobalProvider,
"QuantConnect Exception", exception.ToString());
}
if (result)
{
// lets update the data grid without having to go to the server again
obj.Name = window.BacktestName;
obj.Note = window.BacktestNote;
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Successfully edited backtest");
}
else
{
VsUtils.DisplayInStatusBar(ServiceProvider.GlobalProvider, "Failed to edit backtest");
}
}
}
}
}
}