public async static Task <PacketBase> LoadLocalBacktest(string FileName)
        {
            if (string.IsNullOrEmpty(FileName))
            {
                return(null);
            }
            if (!File.Exists(FileName))
            {
                QCPluginUtilities.OutputCommandString("Backtest file doesn't exist " + FileName, QCPluginUtilities.Severity.Error);
                return(null);
            }

            string json = null;

            using (var reader = File.OpenText(FileName))
                json = await reader.ReadToEndAsync();

            var _results = JsonConvert.DeserializeObject <PacketBase>(json);

            _results.rawData = json;
            if (_results.Errors == null)
            {
                _results.Errors = new List <string>();
            }

            return(_results);
        }
Example #2
0
        public static void UpdateLeanAndComposer(string pluginsPath)
        {
            if (string.IsNullOrEmpty(pluginsPath))
            {
                QCPluginUtilities.OutputCommandString("Lean engine path is empty.", QCPluginUtilities.Severity.Error);
                composer = null;
                lean     = null;
                return;
            }

            if (lean != null && composer != null && pluginsPath == _oldPluginsPath)
            {
                return;
            }

            _oldPluginsPath = pluginsPath;
            QCPluginUtilities.OutputCommandString("Started updating Lean engine and composer...", QCPluginUtilities.Severity.Info);

            AppDomain.CurrentDomain.SetData("APPBASE", pluginsPath);
            Environment.CurrentDirectory = pluginsPath;

            QCPluginUtilities.OutputCommandString("Using ApplicationDomain: " + AppDomain.CurrentDomain.BaseDirectory, QCPluginUtilities.Severity.Info);

            lean = new LeanProxy();
            if (!string.IsNullOrEmpty(pluginsPath))
            {
                lean.LoadLibraries(pluginsPath);

                var objVal = QCPluginUtilities.dte.Properties["QuantConnect Client", "General"].Item("PluginDirectory").Value;
                lean.SetConfiguration("plugin-directory", (string)objVal);
            }
            composer = lean.CreateComposer();

            QCPluginUtilities.OutputCommandString("Finished updating Lean engine and composer...", QCPluginUtilities.Severity.Info);
        }
Example #3
0
        private async void ButtonSave_Click(object sender, EventArgs e)
        {
            buttonLogin.Enabled  = false;
            UseWaitCursor        = true;
            progressBar1.Visible = true;

            if (SuccessCallback != null)
            {
                try
                {
                    await SuccessCallback(textBoxEmail.Text, textBoxPassword.Text, txtUID.Text, txtAuthToken.Text, checkBoxRememberCredentials.Checked);

                    Close();
                }
                catch (Exception ex)
                {
                    progressBar1.Visible = false;
                    buttonLogin.Enabled  = true;
                    QCPluginUtilities.OutputCommandString("Authentication Error: " + ex.ToString(), QCPluginUtilities.Severity.Error);
                }
            }
            else
            {
                Close();
            }
        }
        public static void Logout()
        {
            QCPluginUtilities.OutputCommandString("Removed user credentials.", QCPluginUtilities.Severity.Info);
            api.RemoveAuthentication();
            var credentialFile = Path.Combine(QCPluginUtilities.InstallPath, "credentials.config");

            if (File.Exists(credentialFile))
            {
                File.Delete(credentialFile);
            }
        }
 public async static void Login()
 {
     try
     {
         await Authenticate();
     }
     catch (Exception ex)
     {
         QCPluginUtilities.OutputCommandString("Authentication error: " + ex.ToString(), QCPluginUtilities.Severity.Error);
     }
 }
Example #6
0
        private async void BacktestMenu_Click(object sender, ToolStripItemClickedEventArgs e)
        {
            if (dgrProjects.SelectedRows.Count == 0)
            {
                return;
            }
            var selproj = dgrProjects.SelectedRows[0].DataBoundItem as CombinedProject;

            if (selproj.Id == 0)
            {
                return;
            }

            var sourceControl = e.ClickedItem;

            if (sourceControl.Name == "RefreshBacktestsMenu")
            {
                dgrBacktests.DataSource = null;
                dgrBacktests.DataSource = await QCStudioPluginActions.GetBacktestList(selproj.Id);
            }
            else
            {
                if (dgrBacktests.SelectedRows.Count == 0)
                {
                    return;
                }
                var selbacktest = dgrBacktests.SelectedRows[0].DataBoundItem as BacktestSummary;
                if (string.IsNullOrEmpty(selbacktest.BacktestId) || selbacktest.BacktestId == "0")
                {
                    return;
                }

                switch (sourceControl.Name)
                {
                case "LoadBacktestMenu":
                    QCPluginUtilities.ShowBacktestRemote(selbacktest.BacktestId);

                    break;

                case "DeleteBacktestMenu":
                    await QCStudioPluginActions.DeleteBacktest(selbacktest.BacktestId);

                    RefreshBacktestsMenu.PerformClick();

                    break;

                case "SaveLocallyMenu":
                    await QCStudioPluginActions.SaveRemoteBacktest(selbacktest.BacktestId);

                    break;
                }
            }
        }
        public async static Task DeleteProject(int ProjectID)
        {
            try
            {
                await Authenticate();

                QCPluginUtilities.OutputCommandString("Deleting project...", QCPluginUtilities.Severity.Info);

                await api.ProjectDelete(ProjectID);

                QCPluginUtilities.OutputCommandString("Project deleted successfuly...", QCPluginUtilities.Severity.Info);
            }
            catch (Exception ex)
            {
                QCPluginUtilities.OutputCommandString("Error deleting project: " + ex.ToString(), QCPluginUtilities.Severity.Error);
            }
        }
        public async static Task DeleteBacktest(string BacktestID)
        {
            try
            {
                await Authenticate();

                QCPluginUtilities.OutputCommandString("Deleting backtest...", QCPluginUtilities.Severity.Info);

                await api.BacktestDelete(BacktestID);

                QCPluginUtilities.OutputCommandString("Backtest deleted successfuly...", QCPluginUtilities.Severity.Info);
            }
            catch (Exception ex)
            {
                QCPluginUtilities.OutputCommandString("Error deleting backtest: " + ex.ToString(), QCPluginUtilities.Severity.Error);
            }
        }
        public async static Task <PacketBase> GetBacktestResults(string backtestId)
        {
            try
            {
                QCPluginUtilities.OutputCommandString("getting backtest results...", QCPluginUtilities.Severity.Info);

                var results = await api.BacktestResults(backtestId);

                return(results);
            }
            catch (Exception ex)
            {
                QCPluginUtilities.OutputCommandString("Error getting backtest results: " + ex.ToString(), QCPluginUtilities.Severity.Error);
            }

            return(null);
        }
        public async static Task CreateProject(string projectName)
        {
            try
            {
                await Authenticate();

                QCPluginUtilities.OutputCommandString("Creating project...", QCPluginUtilities.Severity.Info);

                await api.ProjectCreate(projectName);

                QCPluginUtilities.OutputCommandString("Project created successfuly...", QCPluginUtilities.Severity.Info);
            }
            catch (Exception ex)
            {
                QCPluginUtilities.OutputCommandString("Error creating project: " + ex.ToString(), QCPluginUtilities.Severity.Error);
            }
        }
        public async static Task <List <BacktestSummary> > GetBacktestList(int ProjectID)
        {
            try
            {
                await Authenticate();

                QCPluginUtilities.OutputCommandString("Receiving backtests...", QCPluginUtilities.Severity.Info);

                var backtests = await api.BacktestList(ProjectID);

                QCPluginUtilities.OutputCommandString("Backtests received successfuly...", QCPluginUtilities.Severity.Info);

                return(backtests.Summary);
            }
            catch (Exception ex)
            {
                QCPluginUtilities.OutputCommandString("Error receiving backtests: " + ex.ToString(), QCPluginUtilities.Severity.Error);
            }

            return(null);
        }
        public async static Task <bool> CreateBacktest(int ProjectID, string backtestName)
        {
            try
            {
                await Authenticate();

                QCPluginUtilities.OutputCommandString("Building project...", QCPluginUtilities.Severity.Info);
                var res = await api.Compile(ProjectID);

                QCPluginUtilities.OutputCommandString("Running backtest...", QCPluginUtilities.Severity.Info);
                var backtestResult = await api.Backtest(ProjectID, res.CompileId, backtestName);

                if (string.IsNullOrEmpty(backtestResult.BacktestId) || backtestResult.BacktestId == "0")
                {
                    throw new Exception("Failed to run backtest.");
                }

                QCPluginUtilities.OutputCommandString("Project Backtest created.", QCPluginUtilities.Severity.Info);
                return(true);
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
                if (msg.Contains("Time out on build request"))
                {
                    QCPluginUtilities.OutputCommandString("Build timed out, retrying...", QCPluginUtilities.Severity.Warning);
                    return(false);
                }
                else if (msg.Contains("Please upgrade your account"))
                {
                    QCPluginUtilities.OutputCommandString("You have reached the limit of 5 backtests per day via API on a free account. Please upgrade your account to unlock unlimited backtests.", QCPluginUtilities.Severity.Info);
                    return(true);
                }
                else
                {
                    QCPluginUtilities.OutputCommandString("Run backtest error: " + ex.ToString(), QCPluginUtilities.Severity.Error);
                    return(true);
                }
            }
        }
        public async static Task SaveRemoteBacktest(string backtestId)
        {
            await QCStudioPluginActions.Authenticate();

            var _results = await QCStudioPluginActions.GetBacktestResults(backtestId);

            QCPluginUtilities.OutputCommandString("GetBacktestResults succeded: " + _results.Success, QCPluginUtilities.Severity.Info);
            foreach (var err in _results.Errors)
            {
                QCPluginUtilities.OutputCommandString(err, QCPluginUtilities.Severity.Error);
            }

            if (_results != null)
            {
                var dlg = new SaveFileDialog
                {
                    AddExtension = true,
                    Filter       = "JSON file|*.json|All files|*.*",
                    Title        = "Save Backtest results to file"
                };

                if (DialogResult.OK == dlg.ShowDialog())
                {
                    if (string.IsNullOrEmpty(dlg.FileName))
                    {
                        return;
                    }
                    var json = JsonConvert.SerializeObject(_results);
                    File.Delete(dlg.FileName);
                    File.WriteAllText(dlg.FileName, json);
                }
            }
            else
            {
                QCPluginUtilities.OutputCommandString("No backtest results for: " + backtestId, QCPluginUtilities.Severity.Error);
            }
        }
        public async static Task <List <CombinedProject> > GetProjectList()
        {
            try
            {
                await Authenticate();

                QCPluginUtilities.OutputCommandString("Receiving projects...", QCPluginUtilities.Severity.Info);

                var projects = await api.ProjectList();

                QCPluginUtilities.OutputCommandString("Projects received successfuly...", QCPluginUtilities.Severity.Info);

                //FULL OUTER JOIN !!!
                var alookup = QCPluginUtilities.GetAllProjects().Select(x => new KeyValuePair <int, dynamic>(x.Id, x));
                var blookup = projects.Projects.Select(x => new KeyValuePair <int, dynamic>(x.Id, x));

                var combproj = QCPluginUtilities.FullOuterJoin <int>(alookup, blookup);
                return(combproj
                       .Select(x => new CombinedProject
                {
                    Id = x.Item1,
                    Name = x.Item3 != null ? x.Item3.Name : "",
                    CloudProjectName = x.Item3 != null ? x.Item3.Name : "",
                    Modified = x.Item3 != null ? x.Item3.Modified : DateTime.MinValue,
                    LocalProjectName = x.Item2 != null ? x.Item2.name : "",
                    LocalProjectPath = x.Item2 != null ? x.Item2.path : "",
                    uniqueName = x.Item2 != null ? x.Item2.uniqueName : ""
                })
                       .ToList());
            }
            catch (Exception ex)
            {
                QCPluginUtilities.OutputCommandString("Error receiving projects: " + ex.ToString(), QCPluginUtilities.Severity.Error);
            }

            return(null);
        }
        public async static Task SaveLocalBacktest(string pluginsPath, string dataPath)
        {
            string algorithmPath, className;

            QCPluginUtilities.GetSelectedItem(out algorithmPath, out className);
            if (algorithmPath == null || className == null)
            {
                return;
            }

            var json = await LeanActions.RunLocalBacktest(algorithmPath, className, pluginsPath, dataPath);

            if (json != null)
            {
                var dlg = new SaveFileDialog
                {
                    AddExtension = true,
                    Filter       = "JSON file|*.json|All files|*.*",
                    Title        = "Save Backtest results to file"
                };

                if (DialogResult.OK == dlg.ShowDialog())
                {
                    if (string.IsNullOrEmpty(dlg.FileName))
                    {
                        return;
                    }
                    File.Delete(dlg.FileName);
                    File.WriteAllText(dlg.FileName, json);
                }
            }
            else
            {
                QCPluginUtilities.OutputCommandString("No backtest results for: " + className, QCPluginUtilities.Severity.Error);
            }
        }
Example #16
0
        public static Task <string> RunLocalBacktest(string algorithmPath, string fileName, string pluginsPath, string dataPath)
        {
            var statistics = new Dictionary <string, string>();
            var task       = new TaskCompletionSource <string>();

            var tokenSource = new CancellationTokenSource();
            var token       = tokenSource.Token;
            var timer       = DateTime.Now;

            //lean.LoadLibraries(pluginsPath);
            UpdateLeanAndComposer(pluginsPath);
            if (lean == null || composer == null)
            {
                QCPluginUtilities.OutputCommandString("Failed to generate Lean proxy", QCPluginUtilities.Severity.Warning);
                task.SetException(new Exception("Failed to generate proxy"));
                return(task.Task);
            }

            try
            {
                //Config.Set("environment", "");
                lean.SetConfiguration("environment", "");   //"backtesting-desktop"
                lean.SetConfiguration("data-folder", dataPath);
                lean.SetConfiguration("data-directory", dataPath);
                lean.SetConfiguration("algorithm-location", algorithmPath);
                lean.SetConfiguration("algorithm-type-name", fileName);
                //lean.SetConfiguration("api-access-token", "");
                //lean.SetConfiguration("job-user-id", "0");

                var props = TypeDescriptor.GetProperties(typeof(OptionPageGrid)).Cast <PropertyDescriptor>().Where(x => x.Category == "Configuration");
                foreach (var prop in props)
                {
                    var objVal = QCPluginUtilities.dte.Properties["QuantConnect Client", "General"].Item(prop.Name).Value;
                    var strVal = objVal is bool?((bool)objVal).ToString().ToLower() : objVal.ToString();
                    lean.SetConfiguration(prop.DisplayName, strVal);
                }

                //Log.LogHandler = Composer.Instance.GetExportedValueByTypeName<ILogHandler>("QuantConnect.Logging.QueueLogHandler");
                lean.SetLogHandler(composer, (packet) =>
                {
                    var json    = JObject.FromObject(packet);
                    var message = (json["sMessage"] ?? json["Message"] ?? JToken.FromObject("")).Value <string>();
                    var hstack  = (json["sStackTrace"] ?? json["StackTrace"] ?? JToken.FromObject("")).Value <string>();
                    var msgtype = string.IsNullOrEmpty(hstack) ? QCPluginUtilities.Severity.Info : QCPluginUtilities.Severity.Error;

                    QCPluginUtilities.OutputCommandString(message + ", " + hstack, msgtype);
                });

                //var systemHandlers = LeanEngineSystemHandlers.FromConfiguration(Composer.Instance);
                var systemHandlers = lean.CreateLeanEngineSystemHandlers(composer);

                //var algorithmHandlers = LeanEngineAlgorithmHandlers.FromConfiguration(Composer.Instance);
                var algorithmHandlers = lean.CreateLeanEngineAlgorithmHandlers(composer);

                QCPluginUtilities.OutputCommandString("Running " + fileName + "...", QCPluginUtilities.Severity.Info);

                //var _messaging = systemHandlers.Notify;
                lean.AddMessagingEvents(systemHandlers, algorithmHandlers, (packet) =>
                {
                    var json    = JObject.FromObject(packet);
                    var message = (json["sMessage"] ?? json["Message"] ?? JToken.FromObject("")).Value <string>();
                    var hstack  = (json["sStackTrace"] ?? json["StackTrace"] ?? JToken.FromObject("")).Value <string>();
                    var msgtype = string.IsNullOrEmpty(hstack) ? QCPluginUtilities.Severity.Info : QCPluginUtilities.Severity.Error;

                    QCPluginUtilities.OutputCommandString(message + ", " + hstack, msgtype);
                }, (packet) =>
                {
                    var json = JObject.FromObject(packet);
                    if (json["oResults"] == null && json["Results"] == null)
                    {
                        task.SetException(new Exception("No Backend Result!"));
                        return;
                    }

                    var progress = (json["dProgress"] ?? json["Progress"] ?? JToken.FromObject("0")).Value <string>();
                    QCPluginUtilities.OutputCommandString("Backtest progress: " + progress, QCPluginUtilities.Severity.Info);

                    if (progress == "1")
                    {
                        //result.Progress = "100%";
                        var strjson = json.ToString(Formatting.None);
                        if (task.TrySetResult(strjson))
                        {
                            tokenSource.Cancel();
                            (systemHandlers as IDisposable).Dispose();
                            (algorithmHandlers as IDisposable).Dispose();
                        }
                    }
                });

                string _algorithmPath;
                var    job = lean.GetNextJob(systemHandlers, out _algorithmPath);

                //var engine = new Lean.Engine.Engine(systemHandlers, algorithmHandlers, false);
                var engine = lean.CreateEngine(systemHandlers, algorithmHandlers, false);

                Task.Run(() =>
                {
                    try
                    {
                        //engine.Run(job, _algorithmPath);
                        lean.RunEngine(engine, job, _algorithmPath);

                        QCPluginUtilities.OutputCommandString("Finished runnig backtest.", QCPluginUtilities.Severity.Info);
                    }
                    catch (Exception ex)
                    {
                        QCPluginUtilities.OutputCommandString(string.Format("{0} {1}", ex.ToString(), ex.StackTrace), QCPluginUtilities.Severity.Error);
                        task.SetException(ex);
                    }
                }, token);
            }
            catch (Exception ex)
            {
                QCPluginUtilities.OutputCommandString(string.Format("{0} {1}", ex.ToString(), ex.StackTrace), QCPluginUtilities.Severity.Error);
                task.SetException(ex);
            }

            return(task.Task);
        }
        public async static Task Authenticate()
        {
            if (!api.IsAuthenticated)
            {
                var user = new User {
                    Email = "", Password = "", AuthToken = "", UserID = ""
                };
                var credentialFile = Path.Combine(QCPluginUtilities.InstallPath, "credentials.config");

                QCPluginUtilities.OutputCommandString("Authenticating QC user...", QCPluginUtilities.Severity.Info);
                if (File.Exists(credentialFile))
                {
                    var userData = File.ReadAllText(credentialFile);
                    var jsonUser = JsonConvert.DeserializeAnonymousType <User>(userData, user);

                    user.Email     = Encrypter.DecryptString(jsonUser.Email);
                    user.Password  = Encrypter.DecryptString(jsonUser.Password);
                    user.UserID    = Encrypter.DecryptString(jsonUser.UserID);
                    user.AuthToken = Encrypter.DecryptString(jsonUser.AuthToken);
                }

                try
                {
                    await api.Authenticate(user.Email, user.Password, user.UserID, user.AuthToken);
                }
                catch (Exception ex)
                {
                    QCPluginUtilities.OutputCommandString("Authentication error: " + ex.ToString(), QCPluginUtilities.Severity.Error);
                    QCPluginUtilities.OutputCommandString("Failed to authenticate. Enter credentials manually.", QCPluginUtilities.Severity.Info);

                    bool remember = false;
                    var  win      = new FormLogin(user.Email, user.Password, user.UserID, user.AuthToken);
                    win.SuccessCallback = (email2, pass2, uid2, authtoken2, remember2) =>
                    {
                        user.Email     = Encrypter.EncryptString(email2);
                        user.Password  = Encrypter.EncryptString(pass2);
                        user.UserID    = Encrypter.EncryptString(uid2);
                        user.AuthToken = Encrypter.EncryptString(authtoken2);
                        remember       = remember2;

                        return(api.Authenticate(email2, pass2, uid2, authtoken2));
                    };

                    win.ShowDialog();

                    if (!api.IsAuthenticated)
                    {
                        throw new Exception("User authentication failed");
                    }
                    else if (remember)
                    {
                        var jsonUser = JsonConvert.SerializeObject(user);

                        if (File.Exists(credentialFile))
                        {
                            File.Delete(credentialFile);
                        }

                        File.WriteAllText(credentialFile, jsonUser);
                    }
                }

                QCPluginUtilities.OutputCommandString("User authenticated successfuly.", QCPluginUtilities.Severity.Info);
            }
        }
Example #18
0
        private async void ProjectsMenu_Click(object sender, ToolStripItemClickedEventArgs e)
        {
            var sourceControl = e.ClickedItem;

            switch (sourceControl.Name)
            {
            case "CreateProjectMenu":
                string projectName = QCPluginUtilities.GetStartupProjectName();
                projectName = Microsoft.VisualBasic.Interaction.InputBox("Enter new project name", QCPluginUtilities.AppTitle, projectName);
                projectName = CleanInput(projectName);

                if (string.IsNullOrEmpty(projectName))
                {
                    QCPluginUtilities.OutputCommandString("Project name cannot be empty.", QCPluginUtilities.Severity.Error);
                    return;
                }

                await QCStudioPluginActions.CreateProject(projectName);

                RefreshProjectsMenu.PerformClick();

                break;

            case "LoginMenu":
                QCStudioPluginActions.Login();

                break;

            case "LogoutMenu":
                QCStudioPluginActions.Logout();

                break;

            case "RefreshProjectsMenu":
                dgrProjects.DataSource = await QCStudioPluginActions.GetProjectList();

                var firstrow = dgrProjects.Rows.Cast <DataGridViewRow>().FirstOrDefault(x => (x.DataBoundItem as CombinedProject).Id > 0);
                if (firstrow != null)
                {
                    firstrow.Selected = true;
                }

                RefreshBacktestsMenu.PerformClick();

                break;

            case "ConnectProjectIDMenu":
                var projects  = dgrProjects.DataSource as List <CombinedProject>;
                var cloudproj = projects.Where(x => string.IsNullOrEmpty(x.LocalProjectName)).ToArray();
                var localproj = projects.Where(x => x.Id == 0).ToArray();
                if (localproj.Length == 0 || cloudproj.Length == 0)
                {
                    QCPluginUtilities.OutputCommandString("No orphaned projects found on both cloud and local side.", QCPluginUtilities.Severity.Error);
                    return;
                }

                var win = new ConnectQCID();
                win.cmbCloud.Items.AddRange(cloudproj);
                win.cmbLocal.Items.AddRange(localproj);

                if (dgrProjects.SelectedRows.Count > 0)
                {
                    var selproj2 = dgrProjects.SelectedRows[0].DataBoundItem as CombinedProject;
                    win.cmbCloud.SelectedItem = selproj2;
                    win.cmbLocal.SelectedItem = selproj2;
                }

                var dlgres = win.ShowDialog();

                if (dlgres == DialogResult.OK)
                {
                    var selID   = win.cmbCloud.SelectedItem as CombinedProject;
                    var selName = win.cmbLocal.SelectedItem as CombinedProject;

                    QCPluginUtilities.SetProjectID(selID.Id, selName.uniqueName);
                    RefreshProjectsMenu.PerformClick();
                }

                break;

            default:
                if (dgrProjects.SelectedRows.Count == 0)
                {
                    return;
                }
                var selproj = dgrProjects.SelectedRows[0].DataBoundItem as CombinedProject;
                if (selproj.Id == 0)
                {
                    return;
                }

                switch (sourceControl.Name)
                {
                case "DeleteProjectMenu":
                    await QCStudioPluginActions.DeleteProject(selproj.Id);

                    QCPluginUtilities.SetProjectID(0, selproj.uniqueName);
                    RefreshProjectsMenu.PerformClick();

                    break;

                case "UploadProjectMenu":
                    if (string.IsNullOrEmpty(selproj.LocalProjectPath))
                    {
                        return;
                    }
                    await QCStudioPluginActions.UploadProject(selproj.Id, selproj.CloudProjectName, selproj.LocalProjectPath);

                    break;

                case "DownloadProjectMenu":

                    await QCStudioPluginActions.DownloadProject(selproj.Id, selproj.CloudProjectName, selproj.LocalProjectName, selproj.LocalProjectPath);

                    break;

                case "DisconnectProjectIDMenu":
                    QCPluginUtilities.SetProjectID(0, selproj.uniqueName);
                    RefreshProjectsMenu.PerformClick();

                    break;

                case "CompileProjectMenu":
                    string backtestName = QCPluginUtilities.GetStartupProjectName();
                    backtestName = Microsoft.VisualBasic.Interaction.InputBox("Enter new backtest name", QCPluginUtilities.AppTitle, backtestName);
                    backtestName = CleanInput(backtestName);

                    if (string.IsNullOrWhiteSpace(backtestName))
                    {
                        QCPluginUtilities.OutputCommandString("Backtest name cannot be empty.", QCPluginUtilities.Severity.Error);
                        return;
                    }

                    var isfinished = false;
                    var cnt        = 0;
                    while (!isfinished && cnt++ < 5)
                    {
                        isfinished = await QCStudioPluginActions.CreateBacktest(selproj.Id, backtestName);
                    }

                    break;
                }

                break;
            }
        }
        public async static Task DownloadProject(int ProjectID, string cloudProjectName, string ProjectName, string ProjectDir)
        {
            try
            {
                await Authenticate();

                var fileList = new Dictionary <string, string>();
                SavetoCloud_AddSubdirectoryToFileList(ProjectDir, ProjectDir, fileList);
                var cloudfiles = await api.ProjectFiles(ProjectID);

                //FULL OUTER JOIN !!!
                var alookup   = fileList.Select(x => new KeyValuePair <string, dynamic>(x.Key, new QCFile(x.Key, x.Value)));
                var blookup   = cloudfiles.Files.Select(x => new KeyValuePair <string, dynamic>(x.Name, x));
                var combolist = QCPluginUtilities.FullOuterJoin <string>(alookup, blookup);
                var rows      = combolist.Select(x =>
                {
                    var row       = new DataGridViewRow();
                    var chkaction = new DataGridViewCheckBoxCell()
                    {
                        Value = false, Tag = x.Item3
                    };

                    row.Cells.Add(new DataGridViewTextBoxCell()
                    {
                        Value = x.Item3 != null ? x.Item3.Name : ""
                    });
                    row.Cells.Add(chkaction);
                    row.Cells.Add(new DataGridViewTextBoxCell()
                    {
                        Value = x.Item2 != null ? x.Item2.Name : ""
                    });

                    if (x.Item3 == null)
                    {
                        chkaction.Style.BackColor = Color.LightGray;
                        chkaction.ReadOnly        = true;
                    }

                    return(row);
                }).ToArray();

                var form = new ChooseFiles();
                form.Text = "Download files from " + cloudProjectName;
                form.chkAction.HeaderText = "Download";
                form.dgrFiles.Rows.AddRange(rows);
                var res = form.ShowDialog();
                if (res != System.Windows.Forms.DialogResult.OK)
                {
                    return;
                }

                var parsed_filesList = form.dgrFiles.Rows.Cast <DataGridViewRow>()
                                       .Where(x => (x.Cells[1] as DataGridViewCheckBoxCell).Selected)
                                       .Select(x => x.Cells[1].Tag as QCFile)
                                       .ToList();

                QCPluginUtilities.UpdateLocalProject(parsed_filesList, ProjectName);

                QCPluginUtilities.OutputCommandString("Project created successfuly...", QCPluginUtilities.Severity.Info);
            }
            catch (Exception ex)
            {
                QCPluginUtilities.OutputCommandString("Error creating project: " + ex.ToString(), QCPluginUtilities.Severity.Error);
            }
        }