/// <summary> /// This event handler deals with the results of the background operation. /// </summary> private void BgWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (Data.IsIntrabarData || Configs.UseTickData && Data.IsTickData || Data.Period == DataPeriod.M1) { Backtester.Scan(); } if (!CompactMode) { ShowScanningResult(); } CompleteScanning(); if (warningMessage != string.Empty && Configs.CheckData) { MessageBox.Show(warningMessage + Environment.NewLine + Environment.NewLine + Language.T("The data is probably incomplete and the scanning may not be reliable!") + Environment.NewLine + Language.T("You can try also \"Cut Off Bad Data\"."), Language.T("Scanner"), MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (CompactMode) { Close(); } }
/// <summary> /// Sets the navigation buttons /// </summary> private void SetBtnNavigate() { // Buttons "Ambiguous" if (Backtester.AmbiguousBars > 0) { bool isButtonAmbiguous = false; for (int i = Data.FirstBar; i < barCurrent; i++) { if (Backtester.BackTestEval(i) == BacktestEval.Ambiguous) { isButtonAmbiguous = true; break; } } buttonsNavigate[0].Enabled = isButtonAmbiguous; isButtonAmbiguous = false; for (int i = barCurrent + 1; i < Data.Bars; i++) { if (Backtester.BackTestEval(i) == BacktestEval.Ambiguous) { isButtonAmbiguous = true; break; } } buttonsNavigate[5].Enabled = isButtonAmbiguous; } // Buttons "Deals" if (Backtester.PositionsTotal > 0) { bool isButtonDeal = false; for (int i = Data.FirstBar; i < barCurrent; i++) { if (Backtester.Positions(i) > 0) { isButtonDeal = true; break; } } buttonsNavigate[1].Enabled = isButtonDeal; isButtonDeal = false; for (int i = barCurrent + 1; i < Data.Bars; i++) { if (Backtester.Positions(i) > 0) { isButtonDeal = true; break; } } buttonsNavigate[4].Enabled = isButtonDeal; } buttonsNavigate[2].Enabled = barCurrent > Data.FirstBar; buttonsNavigate[3].Enabled = barCurrent < Data.Bars - 1; buttonsNavigate[0].ForeColor = buttonsNavigate[0].Enabled ? Color.Red : buttonsNavigate[2].ForeColor; buttonsNavigate[5].ForeColor = buttonsNavigate[5].Enabled ? Color.Red : buttonsNavigate[2].ForeColor; }
public static void ExportStrategyToIndicator() { var sbLong = new StringBuilder(); var sbShort = new StringBuilder(); for (int bar = Data.FirstBar; bar < Data.Bars; bar++) { for (int pos = 0; pos < Backtester.Positions(bar); pos++) { if (Backtester.PosDir(bar, pos) == PosDirection.Long) { sbLong.AppendLine(" \""+ Data.Time[bar] + "\","); } if (Backtester.PosDir(bar, pos) == PosDirection.Short) { sbShort.AppendLine(" \""+ Data.Time[bar] + "\","); } } } string strategy = Resources.StrategyToIndicator; strategy = strategy.Replace("#MODIFIED#", DateTime.Now.ToString(CultureInfo.InvariantCulture)); strategy = strategy.Replace("#INSTRUMENT#", Data.Symbol); strategy = strategy.Replace("#BASEPERIOD#", Data.DataPeriodToString(Data.Period)); strategy = strategy.Replace("#STARTDATE#", Data.Time[Data.FirstBar].ToString(CultureInfo.InvariantCulture)); strategy = strategy.Replace("#ENDDATE#", Data.Time[Data.Bars - 1].ToString(CultureInfo.InvariantCulture)); strategy = strategy.Replace("#PERIODMINUTES#", ((int)Data.Period).ToString(CultureInfo.InvariantCulture)); strategy = strategy.Replace("#LISTLONG#", sbLong.ToString()); strategy = strategy.Replace("#LISTSHORT#", sbShort.ToString()); var savedlg = new SaveFileDialog { InitialDirectory = Data.SourceFolder, AddExtension = true, Title = Language.T("Custom Indicators"), Filter = Language.T("Custom Indicators") + " (*.cs)|*.cs" }; if (savedlg.ShowDialog() == DialogResult.OK) { strategy = strategy.Replace("#INDICATORNAME#", Path.GetFileNameWithoutExtension(savedlg.FileName)); var sw = new StreamWriter(savedlg.FileName); try { sw.Write(strategy); } catch (Exception exc) { MessageBox.Show(exc.Message, Language.T("Custom Indicators")); } finally { sw.Close(); } } }
/// <summary> /// Calculates the result /// </summary> private void Calculate() { bool isLong = (CbxDirection.SelectedIndex == 0); PosDirection posDir = isLong ? PosDirection.Long : PosDirection.Short; int lotSize = Data.InstrProperties.LotSize; var lots = (double)NudLots.Value; var entryPrice = (double)NudEntryPrice.Value; var exitPrice = (double)NudExitPrice.Value; var daysRollover = (int)NudDays.Value; double point = Data.InstrProperties.Point; string unit = " " + Configs.AccountCurrency; double entryValue = lots * lotSize * entryPrice; double exitValue = lots * lotSize * exitPrice; // Required margin double requiredMargin = (lots * lotSize / Configs.Leverage) * (entryPrice / Backtester.AccountExchangeRate(entryPrice)); AlblOutputValues[0].Text = requiredMargin.ToString("F2") + unit; // Gross Profit double grossProfit = (isLong ? exitValue - entryValue : entryValue - exitValue) / Backtester.AccountExchangeRate(exitPrice); AlblOutputValues[1].Text = grossProfit.ToString("F2") + unit; // Spread double spread = Data.InstrProperties.Spread * point * lots * lotSize / Backtester.AccountExchangeRate(exitPrice); AlblOutputValues[2].Text = spread.ToString("F2") + unit; // Entry Commission double entryCommission = Backtester.CommissionInMoney(lots, entryPrice, false); AlblOutputValues[3].Text = entryCommission.ToString("F2") + unit; // Exit Commission double exitCommission = Backtester.CommissionInMoney(lots, exitPrice, true); AlblOutputValues[4].Text = exitCommission.ToString("F2") + unit; // Rollover double rollover = Backtester.RolloverInMoney(posDir, lots, daysRollover, exitPrice); AlblOutputValues[5].Text = rollover.ToString("F2") + unit; // Slippage double slippage = Data.InstrProperties.Slippage * point * lots * lotSize / Backtester.AccountExchangeRate(exitPrice); AlblOutputValues[6].Text = slippage.ToString("F2") + unit; // Net Profit double netProfit = grossProfit - entryCommission - exitCommission - rollover - slippage; AlblOutputValues[7].Text = netProfit.ToString("F2") + unit; }
/// <summary> /// Resizes the form. /// </summary> protected override void OnLoad(EventArgs e) { base.OnLoad(e); SetBtnNavigate(); for (int bar = Data.FirstBar; bar < Data.Bars; bar++) { if (Backtester.WayPoints(bar) > maxWayPoints) { maxWayPoints = Backtester.WayPoints(bar); } } var btnHrzSpace = (int)(Data.HorizontalDlu * 3); int clientSizeWidth = (Math.Max(aiColumnX[columns] + 2 * btnHrzSpace, 550)); var height = (int)(310 * Data.VDpiScale); ClientSize = new Size(clientSizeWidth, height + infoRowHeight * (maxWayPoints + 2)); }
/// <summary> /// Show position /// </summary> private void ShowPosition(string input) { const string pattern = @"^pos (?<numb>\d+)$"; var expression = new Regex(pattern, RegexOptions.Compiled); Match match = expression.Match(input); if (match.Success) { int pos = int.Parse(match.Groups["numb"].Value); if (pos < 1 || pos > Backtester.PositionsTotal) { return; } Position position = Backtester.PosFromNumb(pos - 1); TbxOutput.Text += "Position" + Environment.NewLine + "-----------------" + Environment.NewLine + position + Environment.NewLine; } }
/// <summary> /// Show position /// </summary> private void ShowOrder(string input) { const string pattern = @"^ord (?<numb>\d+)$"; var expression = new Regex(pattern, RegexOptions.Compiled); Match match = expression.Match(input); if (match.Success) { int ord = int.Parse(match.Groups["numb"].Value); if (ord < 1 || ord > Backtester.OrdersTotal) { return; } Order order = Backtester.OrdFromNumb(ord - 1); TbxOutput.Text += "Order" + Environment.NewLine + "-----------------" + Environment.NewLine + order + Environment.NewLine; } }
/// <summary> /// Loads data and recalculates. /// </summary> protected override void OnShown(EventArgs e) { base.OnShown(e); if (CompactMode) { return; } if (!Data.IsIntrabarData) { StartLoading(); } else { Backtester.Scan(); ShowScanningResult(); ProgressBar.Value = 100; BtnClose.Focus(); } }
/// <summary> /// Sets the chart parameters /// </summary> private void InitChart(int width, int height) { try { Chart = new Bitmap(width, height); if (!Data.IsData || !Data.IsResult || Data.Bars <= Data.FirstBar) { return; } const int border = 1; const int space = 2; int maximum; int minimum; int firstBar = Data.FirstBar; int bars = Data.Bars; int chartBars = Data.Bars - firstBar; int maxBalance = Configs.AccountInMoney ? (int)Backtester.MaxMoneyBalance : Backtester.MaxBalance; int minBalance = Configs.AccountInMoney ? (int)Backtester.MinMoneyBalance : Backtester.MinBalance; int maxEquity = Configs.AccountInMoney ? (int)Backtester.MaxMoneyEquity : Backtester.MaxEquity; int minEquity = Configs.AccountInMoney ? (int)Backtester.MinMoneyEquity : Backtester.MinEquity; if (Configs.AdditionalStatistics) { int maxLongBalance = Configs.AccountInMoney ? (int)Backtester.MaxLongMoneyBalance : Backtester.MaxLongBalance; int minLongBalance = Configs.AccountInMoney ? (int)Backtester.MinLongMoneyBalance : Backtester.MinLongBalance; int maxShortBalance = Configs.AccountInMoney ? (int)Backtester.MaxShortMoneyBalance : Backtester.MaxShortBalance; int minShortBalance = Configs.AccountInMoney ? (int)Backtester.MinShortMoneyBalance : Backtester.MinShortBalance; int maxLsBalance = Math.Max(maxLongBalance, maxShortBalance); int minLsBalance = Math.Min(minLongBalance, minShortBalance); maximum = Math.Max(Math.Max(maxBalance, maxEquity), maxLsBalance) + 1; minimum = Math.Min(Math.Min(minBalance, minEquity), minLsBalance) - 1; } else { maximum = Math.Max(maxBalance, maxEquity) + 1; minimum = Math.Min(minBalance, minEquity) - 1; } const int yTop = border + space; int yBottom = height - border - space; const int xLeft = border; int xRight = width - border - space; float xScale = (xRight - xLeft) / (float)chartBars; float yScale = (yBottom - yTop) / (float)(maximum - minimum); var penBorder = new Pen(Data.GetGradientColor(LayoutColors.ColorCaptionBack, -LayoutColors.DepthCaption), border); var balancePoints = new PointF[chartBars]; var equityPoints = new PointF[chartBars]; var longBalancePoints = new PointF[chartBars]; var shortBalancePoints = new PointF[chartBars]; int index = 0; for (int bar = firstBar; bar < bars; bar++) { balancePoints[index].X = xLeft + index * xScale; equityPoints[index].X = xLeft + index * xScale; if (Configs.AccountInMoney) { balancePoints[index].Y = (float)(yBottom - (Backtester.MoneyBalance(bar) - minimum) * yScale); equityPoints[index].Y = (float)(yBottom - (Backtester.MoneyEquity(bar) - minimum) * yScale); } else { balancePoints[index].Y = yBottom - (Backtester.Balance(bar) - minimum) * yScale; equityPoints[index].Y = yBottom - (Backtester.Equity(bar) - minimum) * yScale; } if (Configs.AdditionalStatistics) { longBalancePoints[index].X = xLeft + index * xScale; shortBalancePoints[index].X = xLeft + index * xScale; if (Configs.AccountInMoney) { longBalancePoints[index].Y = (float)(yBottom - (Backtester.LongMoneyBalance(bar) - minimum) * yScale); shortBalancePoints[index].Y = (float)(yBottom - (Backtester.ShortMoneyBalance(bar) - minimum) * yScale); } else { longBalancePoints[index].Y = yBottom - (Backtester.LongBalance(bar) - minimum) * yScale; shortBalancePoints[index].Y = yBottom - (Backtester.ShortBalance(bar) - minimum) * yScale; } } index++; } Graphics g = Graphics.FromImage(Chart); // Paints the background by gradient var rectField = new RectangleF(1, 1, width - 2, height - 2); g.FillRectangle(new SolidBrush(LayoutColors.ColorChartBack), rectField); // Border g.DrawRectangle(penBorder, 0, 0, width - 1, height - 1); // Equity line g.DrawLines(new Pen(LayoutColors.ColorChartEquityLine), equityPoints); // Draw Long and Short balance if (Configs.AdditionalStatistics) { g.DrawLines(new Pen(Color.Red), shortBalancePoints); g.DrawLines(new Pen(Color.Green), longBalancePoints); } // Draw the balance line g.DrawLines(new Pen(LayoutColors.ColorChartBalanceLine), balancePoints); } catch { } }
/// <summary> /// Calculates the selected indicator. /// </summary> private void CalculateIndicator(bool bCalculateStrategy) { if (!Data.IsData || !Data.IsResult || !isPaint) { return; } SetOppositeSignalBehaviour(); SetClosingLogicConditions(); Indicator indicator = IndicatorManager.ConstructIndicator(indicatorName); indicator.Initialize(slotType); // List parameters for (int i = 0; i < 5; i++) { indicator.IndParam.ListParam[i].Index = ListParam[i].SelectedIndex; indicator.IndParam.ListParam[i].Text = ListParam[i].Text; indicator.IndParam.ListParam[i].Enabled = ListParam[i].Enabled; } // Numeric parameters for (int i = 0; i < 6; i++) { indicator.IndParam.NumParam[i].Value = (double)NumParam[i].Value; indicator.IndParam.NumParam[i].Enabled = NumParam[i].Enabled; } // Check parameters for (int i = 0; i < 2; i++) { indicator.IndParam.CheckParam[i].Checked = CheckParam[i].Checked; indicator.IndParam.CheckParam[i].Enabled = CheckParam[i].Enabled; indicator.IndParam.CheckParam[i].Enabled = CheckParam[i].Text == "Use previous bar value" || CheckParam[i].Enabled; } if (!CalculateIndicator(slotType, indicator)) { return; } if (bCalculateStrategy) { //Sets Data.Strategy Data.Strategy.Slot[slot].IndicatorName = indicator.IndicatorName; Data.Strategy.Slot[slot].IndParam = indicator.IndParam; Data.Strategy.Slot[slot].Component = indicator.Component; Data.Strategy.Slot[slot].SeparatedChart = indicator.SeparatedChart; Data.Strategy.Slot[slot].SpecValue = indicator.SpecialValues; Data.Strategy.Slot[slot].MinValue = indicator.SeparatedChartMinValue; Data.Strategy.Slot[slot].MaxValue = indicator.SeparatedChartMaxValue; Data.Strategy.Slot[slot].IsDefined = true; // Search the indicators' components to determine Data.FirstBar Data.FirstBar = Data.Strategy.SetFirstBar(); // Check "Use previous bar value" if (Data.Strategy.AdjustUsePreviousBarValue()) { for (int i = 0; i < 2; i++) { if (indicator.IndParam.CheckParam[i].Caption == "Use previous bar value") { AChbCheck[i].Checked = Data.Strategy.Slot[slot].IndParam.CheckParam[i].Checked; } } } Backtester.Calculate(); Backtester.CalculateAccountStats(); } SetIndicatorNotification(indicator); Data.IsResult = true; }
/// <summary> /// Calculates the balance lines /// </summary> private int Calculate(BackgroundWorker worker) { // Determine the number of lines // For each method per line // The random line shows the averaged values // Also we have two border lines for the random method // Plus the average balance line isRandom = false; minimum = float.MaxValue; maximum = float.MinValue; minimumRandom = float.MaxValue; maximumRandom = float.MinValue; var randomLines = (int)NumRandom.Value; checkedMethods = 0; lines = 1; for (int m = 0; m < countMethods; m++) { if (AchboxMethods[m].Checked) { checkedMethods++; lines++; if ((InterpolationMethod)AchboxMethods[m].Tag == InterpolationMethod.Random) { isRandom = true; } } } if (checkedMethods == 0 && Configs.PlaySounds) { SystemSounds.Hand.Play(); return(-1); } afBalance = new float[Data.Bars - Data.FirstBar]; afMethods = new float[countMethods, Data.Bars - Data.FirstBar]; if (isRandom) { afRandoms = new float[randomLines, Data.Bars - Data.FirstBar]; afMinRandom = new float[Data.Bars - Data.FirstBar]; afMaxRandom = new float[Data.Bars - Data.FirstBar]; } // Progress parameters int computedCycles = 0; int cycles = lines + (isRandom ? randomLines : 0); int highestPercentageReached = 0; int percentComplete; // Calculates the lines for (int m = 0; m < countMethods; m++) { if (worker.CancellationPending) { return(-1); } if (!AchboxMethods[m].Checked) { continue; } var method = (InterpolationMethod)AchboxMethods[m].Tag; if (method == InterpolationMethod.Random) { for (int r = 0; r < randomLines; r++) { if (worker.CancellationPending) { return(-1); } Backtester.InterpolationMethod = method; Backtester.Calculate(); if (Configs.AccountInMoney) { for (int iBar = 0; iBar < Data.Bars - Data.FirstBar; iBar++) { afRandoms[r, iBar] = (float)Backtester.MoneyBalance(iBar + Data.FirstBar); } } else { for (int iBar = 0; iBar < Data.Bars - Data.FirstBar; iBar++) { afRandoms[r, iBar] = Backtester.Balance(iBar + Data.FirstBar); } } // Report progress as a percentage of the total task. computedCycles++; percentComplete = 100 * computedCycles / cycles; percentComplete = percentComplete > 100 ? 100 : percentComplete; if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; worker.ReportProgress(percentComplete); } } for (int iBar = 0; iBar < Data.Bars - Data.FirstBar; iBar++) { float randomSum = 0; float minRandom = float.MaxValue; float maxRandom = float.MinValue; for (int r = 0; r < randomLines; r++) { float value = afRandoms[r, iBar]; randomSum += value; minRandom = value < minRandom ? value : minRandom; maxRandom = value > maxRandom ? value : maxRandom; } afMethods[m, iBar] = randomSum / randomLines; afMinRandom[iBar] = minRandom; afMaxRandom[iBar] = maxRandom; minimumRandom = minRandom < minimumRandom ? minRandom : minimumRandom; maximumRandom = maxRandom > maximumRandom ? maxRandom : maximumRandom; } // Report progress as a percentage of the total task. computedCycles++; percentComplete = 100 * computedCycles / cycles; percentComplete = percentComplete > 100 ? 100 : percentComplete; if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; worker.ReportProgress(percentComplete); } } else { Backtester.InterpolationMethod = method; Backtester.Calculate(); if (Configs.AccountInMoney) { for (int iBar = 0; iBar < Data.Bars - Data.FirstBar; iBar++) { afMethods[m, iBar] = (float)Backtester.MoneyBalance(iBar + Data.FirstBar); } } else { for (int iBar = 0; iBar < Data.Bars - Data.FirstBar; iBar++) { afMethods[m, iBar] = Backtester.Balance(iBar + Data.FirstBar); } } // Report progress as a percentage of the total task. computedCycles++; percentComplete = 100 * computedCycles / cycles; percentComplete = percentComplete > 100 ? 100 : percentComplete; if (percentComplete > highestPercentageReached) { highestPercentageReached = percentComplete; worker.ReportProgress(percentComplete); } } } // Calculates the average balance, Min and Max for (int bar = 0; bar < Data.Bars - Data.FirstBar; bar++) { float sum = 0; for (int m = 0; m < countMethods; m++) { if (!AchboxMethods[m].Checked) { continue; } float value = afMethods[m, bar]; sum += value; if (value < minimum) { minimum = value; } if (value > maximum) { maximum = value; } } afBalance[bar] = sum / checkedMethods; } // Report progress as a percentage of the total task. computedCycles++; percentComplete = 100 * computedCycles / cycles; percentComplete = percentComplete > 100 ? 100 : percentComplete; if (percentComplete > highestPercentageReached) { worker.ReportProgress(percentComplete); } return(0); }
/// <summary> /// Initialize the form and controls /// </summary> public BarExplorer(int barNumber) { pnlChart = new Panel(); pnlInfo = new Panel(); toolTip = new ToolTip(); barCurrent = barNumber < Data.FirstBar ? Data.FirstBar : barNumber; Text = Language.T("Bar Explorer"); BackColor = LayoutColors.ColorFormBack; FormBorderStyle = FormBorderStyle.FixedDialog; Icon = Data.Icon; MaximizeBox = false; MinimizeBox = false; ShowInTaskbar = false; fontInfo = new Font(Font.FontFamily, 9); infoRowHeight = Math.Max(fontInfo.Height, 18); barInfo = Language.T("Bar") + ": " + (barCurrent + 1) + " " + Data.Time[barCurrent].ToString(Data.Df) + " " + Data.Time[barCurrent].ToString("HH:mm") + "; " + Language.T("Interpolation method") + ": " + Backtester.InterpolationMethodToString(); pnlChart.Parent = this; pnlChart.Paint += PnlChartPaint; pnlInfo.Parent = this; pnlInfo.Paint += PnlInfoPaint; buttonsNavigate = new Button[6]; var btnNavigateText = new[] { "< !", "<<", "<", ">", ">>", "! >" }; var btnNavigateTips = new[] { Language.T("Previous ambiguous bar."), Language.T("Previous deal."), Language.T("Previous bar."), Language.T("Next bar."), Language.T("Next deal."), Language.T("Next ambiguous bar.") }; for (int i = 0; i < 6; i++) { buttonsNavigate[i] = new Button { Parent = this, Text = btnNavigateText[i], Name = btnNavigateText[i] }; buttonsNavigate[i].Click += BtnNavigateClick; buttonsNavigate[i].MouseWheel += BarExplorerMouseWheel; buttonsNavigate[i].KeyUp += BtnNavigateKeyUp; buttonsNavigate[i].UseVisualStyleBackColor = true; toolTip.SetToolTip(buttonsNavigate[i], btnNavigateTips[i]); } buttonsNavigate[0].Enabled = Backtester.AmbiguousBars > 0; buttonsNavigate[1].Enabled = Backtester.PositionsTotal > 0; buttonsNavigate[4].Enabled = Backtester.PositionsTotal > 0; buttonsNavigate[5].Enabled = Backtester.AmbiguousBars > 0; nudGo = new NumericUpDown { Parent = this, TextAlign = HorizontalAlignment.Center }; nudGo.BeginInit(); nudGo.Minimum = Data.FirstBar + 1; nudGo.Maximum = Data.Bars; nudGo.Increment = 1; nudGo.Value = barCurrent + 1; nudGo.KeyUp += BtnNavigateKeyUp; nudGo.EndInit(); btnGo = new Button { Parent = this, Name = "Go", Text = Language.T("Go"), UseVisualStyleBackColor = true }; btnGo.Click += BtnNavigateClick; btnGo.MouseWheel += BarExplorerMouseWheel; btnGo.KeyUp += BtnNavigateKeyUp; toolTip.SetToolTip(btnGo, Language.T("Go to the chosen bar.")); //Button Close btnClose = new Button { Parent = this, Text = Language.T("Close"), DialogResult = DialogResult.Cancel, UseVisualStyleBackColor = true }; // Colors brushRed = new SolidBrush(LayoutColors.ColorSignalRed); brushCaptionText = new SolidBrush(LayoutColors.ColorCaptionText); brushEvenRow = new SolidBrush(LayoutColors.ColorEvenRowBack); brushGridText = new SolidBrush(LayoutColors.ColorChartFore); penGrid = new Pen(LayoutColors.ColorChartGrid) { DashStyle = DashStyle.Dash, DashPattern = new float[] { 4, 2 } }; penAxes = new Pen(LayoutColors.ColorChartFore); penCross = new Pen(LayoutColors.ColorChartCross); penBarBorder = new Pen(LayoutColors.ColorBarBorder); colorBarWight1 = Data.GetGradientColor(LayoutColors.ColorBarWhite, 30); colorBarWight2 = Data.GetGradientColor(LayoutColors.ColorBarWhite, -30); colorBarBlack1 = Data.GetGradientColor(LayoutColors.ColorBarBlack, 30); colorBarBlack2 = Data.GetGradientColor(LayoutColors.ColorBarBlack, -30); colorLongTrade1 = Data.GetGradientColor(LayoutColors.ColorTradeLong, 30); colorLongTrade2 = Data.GetGradientColor(LayoutColors.ColorTradeLong, -30); colorShortTrade1 = Data.GetGradientColor(LayoutColors.ColorTradeShort, 30); colorShortTrade2 = Data.GetGradientColor(LayoutColors.ColorTradeShort, -30); colorClosedTrade1 = Data.GetGradientColor(LayoutColors.ColorTradeClose, 30); colorClosedTrade2 = Data.GetGradientColor(LayoutColors.ColorTradeClose, -30); SetJournalPoints(); }
/// <summary> /// Paints panel pnlChart /// </summary> private void PnlChartPaint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; g.Clear(LayoutColors.ColorChartBack); if (!Data.IsData || !Data.IsResult) { return; } var pnl = (Panel)sender; int width = pnl.ClientSize.Width; // Caption background var pntStart = new PointF(0, 0); SizeF szfCaption = new Size(width, infoRowHeight); var rectCaption = new RectangleF(pntStart, szfCaption); Data.GradientPaint(g, rectCaption, LayoutColors.ColorCaptionBack, LayoutColors.DepthCaption); // Caption Text var stringFormat = new StringFormat { LineAlignment = StringAlignment.Center, Trimming = StringTrimming.EllipsisCharacter, FormatFlags = StringFormatFlags.NoWrap, Alignment = StringAlignment.Center }; string stringCaptionText = Language.T("Price Route Inside the Bar"); rectCaption = new RectangleF(Border, 0, pnl.ClientSize.Width - 2 * Border, infoRowHeight); g.DrawString(stringCaptionText, fontInfo, brushCaptionText, rectCaption, stringFormat); // Paint the panel background var rectClient = new RectangleF(0, infoRowHeight, pnl.ClientSize.Width, pnl.Height - infoRowHeight); Data.GradientPaint(g, rectClient, LayoutColors.ColorChartBack, LayoutColors.DepthControl); // Paint bar info var rectBarInfo = new RectangleF(Border, infoRowHeight + 1, pnl.ClientSize.Width - 2 * Border, infoRowHeight); g.DrawString(barInfo, fontInfo, brushGridText, rectBarInfo, stringFormat); // Searching the min and the max price and volume width = pnl.ClientSize.Width - 2 * Border; double maxPrice = Data.High[barCurrent]; double minPrice = Data.Low[barCurrent]; const int space = 8; int spcRight = szPrice.Width + 4; const int xLeft = Border + space; int xRight = width - spcRight; int yTop = 2 * infoRowHeight + 6; int yBottom = pnl.ClientSize.Height - 22; int barPixels = maxWayPoints < 10 ? 28 : maxWayPoints < 15 ? 24 : 20; const int spcLeft = 3; int x = barPixels + spcLeft; int pointLeft = x + barPixels + 30; int pointRight = xRight - 20; int points = Backtester.WayPoints(barCurrent); const int pointRadius = 3; // Grid var iCntLabels = (int)Math.Max((yBottom - yTop) / 30d, 1); double deltaPoint = (Data.InstrProperties.Digits == 5 || Data.InstrProperties.Digits == 3) ? Data.InstrProperties.Point * 100 : Data.InstrProperties.Point * 10; double delta = Math.Max(Math.Round((maxPrice - minPrice) / iCntLabels, Data.InstrProperties.Point < 0.001 ? 3 : 1), deltaPoint); minPrice = Math.Round(minPrice, Data.InstrProperties.Point < 0.001f ? 3 : 1) - Data.InstrProperties.Point * 10; minPrice -= delta; maxPrice += delta; iCntLabels = (int)Math.Ceiling((maxPrice - minPrice) / delta); maxPrice = minPrice + iCntLabels * delta; double scaleY = (yBottom - yTop) / (iCntLabels * delta); var yOpen = (int)(yBottom - (Data.Open[barCurrent] - minPrice) * scaleY); var yHigh = (int)(yBottom - (Data.High[barCurrent] - minPrice) * scaleY); var yLow = (int)(yBottom - (Data.Low[barCurrent] - minPrice) * scaleY); var yClose = (int)(yBottom - (Data.Close[barCurrent] - minPrice) * scaleY); // Find the price distance double priceDistance = 0; for (int point = 1; point < points; point++) { priceDistance += Math.Abs(Backtester.WayPoint(barCurrent, point).Price - Backtester.WayPoint(barCurrent, point - 1).Price); } double dPriceForAPixel = (pointRight - pointLeft) / priceDistance; // Points X var aiPointX = new int[points]; aiPointX[0] = pointLeft; for (int point = 1; point < points - 1; point++) { var iDistance = (int) (Math.Abs(Backtester.WayPoint(barCurrent, point).Price - Backtester.WayPoint(barCurrent, point - 1).Price) * dPriceForAPixel); aiPointX[point] = aiPointX[point - 1] + iDistance; } aiPointX[points - 1] = pointRight; for (int point = 1; point < points - 1; point++) { if (aiPointX[point] - aiPointX[point - 1] < barPixels + 1) { aiPointX[point] = aiPointX[point - 1] + barPixels + 1; } } for (int point = points - 2; point > 0; point--) { if (aiPointX[point + 1] - aiPointX[point] < barPixels + 1) { aiPointX[point] = aiPointX[point + 1] - barPixels - 1; } } // Find coordinates of the Way Points var pntWay = new Point[points]; for (int point = 0; point < points; point++) { var pointY = (int)(yBottom - (Backtester.WayPoint(barCurrent, point).Price - minPrice) * scaleY); pntWay[point] = new Point(aiPointX[point], pointY); } // Horizontal grid and Price labels for (double label = minPrice; label <= maxPrice + Data.InstrProperties.Point; label += delta) { var labelY = (int)(yBottom - (label - minPrice) * scaleY); g.DrawString(label.ToString(Data.Ff), Font, brushGridText, xRight, labelY - Font.Height / 2 - 1); g.DrawLine(penGrid, Border + space, labelY, xRight, labelY); } // Vertical Grid g.DrawLine(penGrid, x + barPixels / 2 - 1, yTop, x + barPixels / 2 - 1, yBottom + 2); for (int point = 0; point < points; point++) { var pt1 = new Point(pntWay[point].X, yTop); var pt2 = new Point(pntWay[point].X, yBottom + 2); var pt3 = new Point(pntWay[point].X - 5, yBottom + 4); g.DrawLine(penGrid, pt1, pt2); g.DrawString((point + 1).ToString(CultureInfo.InvariantCulture), Font, brushGridText, pt3); } // Bar Number string barNumber = (barCurrent + 1).ToString(CultureInfo.InvariantCulture); int stringX = x + barPixels / 2 - 1 - g.MeasureString(barNumber, Font).ToSize().Width / 2; Brush barBrush = Backtester.BackTestEval(barCurrent) == BacktestEval.Ambiguous ? brushRed : brushGridText; g.DrawString(barNumber, Font, barBrush, stringX, yBottom + 4); // Draw the bar g.DrawLine(penBarBorder, x + barPixels / 2 - 1, yLow, x + barPixels / 2 - 1, yHigh); if (yClose < yOpen) // White bar { var rect = new Rectangle(x, yClose, barPixels - 2, yOpen - yClose); var lgBrush = new LinearGradientBrush(rect, colorBarWight1, colorBarWight2, 5f); g.FillRectangle(lgBrush, rect); g.DrawRectangle(penBarBorder, x, yClose, barPixels - 2, yOpen - yClose); } else if (yClose > yOpen) // Black bar { var rect = new Rectangle(x, yOpen, barPixels - 2, yClose - yOpen); var lgBrush = new LinearGradientBrush(rect, colorBarBlack1, colorBarBlack2, 5f); g.FillRectangle(lgBrush, rect); g.DrawRectangle(penBarBorder, x, yOpen, barPixels - 2, yClose - yOpen); } else // Cross { g.DrawLine(penBarBorder, x, yClose, x + barPixels - 2, yClose); } // Draw cancelled orders for (int orderIndex = 0; orderIndex < Backtester.Orders(barCurrent); orderIndex++) { int ordNumber = Backtester.OrdNumb(barCurrent, orderIndex); Order order = Backtester.OrdFromNumb(ordNumber); if (order.OrdStatus != OrderStatus.Cancelled) { continue; } if (order.OrdPrice > Data.High[barCurrent] || order.OrdPrice < Data.Low[barCurrent]) { continue; } int d = barPixels / 2 - 1; int x1 = x + d; int x2 = x + barPixels - 2; var yDeal = (int)(yBottom - (order.OrdPrice - minPrice) * scaleY); var pen = new Pen(LayoutColors.ColorChartGrid, 2); if (order.OrdDir == OrderDirection.Buy) { g.DrawLine(pen, x, yDeal, x1, yDeal); g.DrawLine(pen, x1, yDeal, x2, yDeal - d); g.DrawLine(pen, x2 + 1, yDeal - d + 1, x1 + d / 2 + 1, yDeal - d + 1); g.DrawLine(pen, x2, yDeal - d, x2, yDeal - d / 2); } else if (order.OrdDir == OrderDirection.Sell) { g.DrawLine(pen, x, yDeal + 1, x1 + 1, yDeal + 1); g.DrawLine(pen, x1, yDeal, x2, yDeal + d); g.DrawLine(pen, x1 + d / 2 + 1, yDeal + d, x2, yDeal + d); g.DrawLine(pen, x2, yDeal + d, x2, yDeal + d / 2 + 1); } } // Draw the deals on the bar for (int pos = 0; pos < Backtester.Positions(barCurrent); pos++) { if (Backtester.PosTransaction(barCurrent, pos) == Transaction.Transfer) { continue; } var yDeal = (int)(yBottom - (Backtester.PosOrdPrice(barCurrent, pos) - minPrice) * scaleY); if (Backtester.PosDir(barCurrent, pos) == PosDirection.Long || Backtester.PosDir(barCurrent, pos) == PosDirection.Short) { int d = barPixels / 2 - 1; int x1 = x + d; int x2 = x + barPixels - 2; if (Backtester.OrdFromNumb(Backtester.PosOrdNumb(barCurrent, pos)).OrdDir == OrderDirection.Buy) { // Buy var pen = new Pen(LayoutColors.ColorTradeLong, 2); g.DrawLine(pen, x, yDeal, x1, yDeal); g.DrawLine(pen, x1, yDeal, x2, yDeal - d); g.DrawLine(pen, x2 + 1, yDeal - d + 1, x1 + d / 2 + 1, yDeal - d + 1); g.DrawLine(pen, x2, yDeal - d, x2, yDeal - d / 2); } else { // Sell var pen = new Pen(LayoutColors.ColorTradeShort, 2); g.DrawLine(pen, x, yDeal + 1, x1 + 1, yDeal + 1); g.DrawLine(pen, x1, yDeal, x2, yDeal + d); g.DrawLine(pen, x1 + d / 2 + 1, yDeal + d, x2, yDeal + d); g.DrawLine(pen, x2, yDeal + d, x2, yDeal + d / 2 + 1); } } else if (Backtester.PosDir(barCurrent, pos) == PosDirection.Closed) { // Close position int d = barPixels / 2 - 1; int x1 = x + d; int x2 = x + barPixels - 3; var pen = new Pen(LayoutColors.ColorTradeClose, 2); g.DrawLine(pen, x, yDeal, x1, yDeal); g.DrawLine(pen, x1, yDeal + d / 2, x2, yDeal - d / 2); g.DrawLine(pen, x1, yDeal - d / 2, x2, yDeal + d / 2); } } // Draw position lots for (int point = 0; point < points; point++) { int posNumber = Backtester.WayPoint(barCurrent, point).PosNumb; if (posNumber == -1) { continue; } Position position = Backtester.PosFromNumb(posNumber); double posLots = position.PosLots; PosDirection posDirection = position.PosDir; WayPointType wpType = Backtester.WayPoint(barCurrent, point).WpType; var height = (int)(Math.Max(posLots * 2, 2)); int length = barPixels; int posX = pntWay[point].X - (barPixels - 1) / 2; int posY = yBottom - height; if (point < points - 1) { length = pntWay[point + 1].X - pntWay[point].X + 1; } if (posDirection == PosDirection.Long) { // Long var rect = new Rectangle(posX - 1, posY - 1, length, height + 2); var lgBrush = new LinearGradientBrush(rect, colorLongTrade1, colorLongTrade2, LinearGradientMode.Vertical); rect = new Rectangle(posX - 1, posY, length, height); g.FillRectangle(lgBrush, rect); } else if (posDirection == PosDirection.Short) { // Short var rect = new Rectangle(posX - 1, posY - 1, length, height + 2); var lgBrush = new LinearGradientBrush(rect, colorShortTrade1, colorShortTrade2, LinearGradientMode.Vertical); rect = new Rectangle(posX - 1, posY, length, height); g.FillRectangle(lgBrush, rect); } else if (posDirection == PosDirection.Closed && wpType == WayPointType.Exit) { // Closed var rect = new Rectangle(posX - 1, yBottom - 2, barPixels + 1, 2); var lgBrush = new LinearGradientBrush(rect, colorClosedTrade1, colorClosedTrade2, LinearGradientMode.Vertical); rect = new Rectangle(posX, yBottom - 2, barPixels - 1, 2); g.FillRectangle(lgBrush, rect); } } // Draw the Beziers for (int point = 1; point < points; point++) { Point ptKnot1 = pntWay[point - 1]; Point ptKnot2 = pntWay[point]; int ctrlX1 = (ptKnot1.X + ptKnot2.X) / 2; int ctrlX2 = (ptKnot1.X + ptKnot2.X) / 2; int ctrlY1 = ptKnot1.Y; int ctrlY2 = ptKnot2.Y; if (point > 1) { if (pntWay[point - 2].Y > pntWay[point - 1].Y && pntWay[point - 1].Y > pntWay[point].Y || pntWay[point - 2].Y < pntWay[point - 1].Y && pntWay[point - 1].Y < pntWay[point].Y) { ctrlY1 = (pntWay[point - 1].Y + pntWay[point].Y) / 2; } } if (point < points - 1) { if (pntWay[point - 1].Y > pntWay[point].Y && pntWay[point].Y > pntWay[point + 1].Y || pntWay[point - 1].Y < pntWay[point].Y && pntWay[point].Y < pntWay[point + 1].Y) { ctrlY2 = (pntWay[point - 1].Y + pntWay[point].Y) / 2; } } if (point == 1) { ctrlX1 = ptKnot1.X; ctrlY1 = ptKnot1.Y; } if (point == points - 1) { ctrlX2 = ptKnot2.X; ctrlY2 = ptKnot2.Y; } var ptControl1 = new Point(ctrlX1, ctrlY1); var ptControl2 = new Point(ctrlX2, ctrlY2); g.DrawBezier(penCross, ptKnot1, ptControl1, ptControl2, ptKnot2); } // Draw the WayPoints Brush brushWeyPnt = new SolidBrush(LayoutColors.ColorChartBack); for (int point = 0; point < points; point++) { g.FillEllipse(brushWeyPnt, pntWay[point].X - pointRadius, pntWay[point].Y - pointRadius, 2 * pointRadius, 2 * pointRadius); g.DrawEllipse(penCross, pntWay[point].X - pointRadius, pntWay[point].Y - pointRadius, 2 * pointRadius, 2 * pointRadius); } // Draw O, H, L, C labels for (int point = 0; point < points; point++) { WayPointType wpType = Backtester.WayPoint(barCurrent, point).WpType; if (wpType != WayPointType.Open && wpType != WayPointType.High && wpType != WayPointType.Low && wpType != WayPointType.Close) { continue; } string label = "?"; switch (wpType) { case WayPointType.Open: label = "O"; break; case WayPointType.High: label = "H"; break; case WayPointType.Low: label = "L"; break; case WayPointType.Close: label = "C"; break; } int xPoint = pntWay[point].X; int yPoint = pntWay[point].Y - Font.Height - 3; var stringFormatLabel = new StringFormat { Alignment = StringAlignment.Center }; g.DrawString(label, Font, brushGridText, xPoint, yPoint, stringFormatLabel); } // Draw the deals on the route for (int point = 0; point < points; point++) { int posNumber = Backtester.WayPoint(barCurrent, point).PosNumb; int ordNumber = Backtester.WayPoint(barCurrent, point).OrdNumb; if (posNumber < 0 || ordNumber < 0) { continue; } PosDirection posDirection = Backtester.PosFromNumb(posNumber).PosDir; OrderDirection ordDirection = Backtester.OrdFromNumb(ordNumber).OrdDir; WayPointType wpType = Backtester.WayPoint(barCurrent, point).WpType; if (wpType == WayPointType.None || wpType == WayPointType.Open || wpType == WayPointType.High || wpType == WayPointType.Low || wpType == WayPointType.Close) { continue; } int yDeal = pntWay[point].Y; if (posDirection == PosDirection.Long || posDirection == PosDirection.Short || wpType == WayPointType.Cancel) { int d = barPixels / 2 - 1; x = pntWay[point].X - d; int x1 = pntWay[point].X; int x2 = x + barPixels - 2; if (ordDirection == OrderDirection.Buy) { // Buy var pen = new Pen(LayoutColors.ColorTradeLong, 2); if (wpType == WayPointType.Cancel) { pen = new Pen(LayoutColors.ColorChartGrid, 2); } g.DrawLine(pen, x, yDeal, x1, yDeal); g.DrawLine(pen, x1, yDeal, x2, yDeal - d); g.DrawLine(pen, x2 + 1, yDeal - d + 1, x1 + d / 2 + 1, yDeal - d + 1); g.DrawLine(pen, x2, yDeal - d, x2, yDeal - d / 2); } else { // Sell var pen = new Pen(LayoutColors.ColorTradeShort, 2); if (wpType == WayPointType.Cancel) { pen = new Pen(LayoutColors.ColorChartGrid, 2); } g.DrawLine(pen, x, yDeal + 1, x1 + 1, yDeal + 1); g.DrawLine(pen, x1, yDeal, x2, yDeal + d); g.DrawLine(pen, x1 + d / 2 + 1, yDeal + d, x2, yDeal + d); g.DrawLine(pen, x2, yDeal + d, x2, yDeal + d / 2 + 1); } } if (posDirection == PosDirection.Closed) { // Close position int d = barPixels / 2 - 1; x = pntWay[point].X - d; int x1 = pntWay[point].X; int x2 = x + barPixels - 3; var pen = new Pen(LayoutColors.ColorTradeClose, 2); g.DrawLine(pen, x, yDeal, x1, yDeal); g.DrawLine(pen, x1, yDeal + d / 2, x2, yDeal - d / 2); g.DrawLine(pen, x1, yDeal - d / 2, x2, yDeal + d / 2); } } // Coordinate axes g.DrawLine(penAxes, xLeft, yTop - 4, xLeft, yBottom); // Vertical left line g.DrawLine(penAxes, xLeft, yBottom, xRight, yBottom); // Border var penBorder = new Pen(Data.GetGradientColor(LayoutColors.ColorCaptionBack, -LayoutColors.DepthCaption), Border); g.DrawLine(penBorder, 1, infoRowHeight, 1, pnl.ClientSize.Height); g.DrawLine(penBorder, pnl.ClientSize.Width - Border + 1, infoRowHeight, pnl.ClientSize.Width - Border + 1, pnl.ClientSize.Height); g.DrawLine(penBorder, 0, pnl.ClientSize.Height - Border + 1, pnl.ClientSize.Width, pnl.ClientSize.Height - Border + 1); }
/// <summary> /// Represents the Strategy as a XmlDocument. /// </summary> public static XmlDocument CreateStrategyXmlDoc(Strategy strategy) { // Create the XmlDocument. var xmlDocStrategy = new XmlDocument(); xmlDocStrategy.LoadXml("<strategy></strategy>"); //Create the XML declaration. XmlDeclaration xmldecl = xmlDocStrategy.CreateXmlDeclaration("1.0", null, null); //Add new node to the document. XmlElement root = xmlDocStrategy.DocumentElement; xmlDocStrategy.InsertBefore(xmldecl, root); AppendStringElement(xmlDocStrategy, "programName", Data.ProgramName); AppendStringElement(xmlDocStrategy, "programVersion", Data.ProgramVersion); AppendStringElement(xmlDocStrategy, "strategyName", strategy.StrategyName); AppendStringElement(xmlDocStrategy, "instrumentSymbol", strategy.Symbol); AppendStringElement(xmlDocStrategy, "instrumentPeriod", (int)strategy.DataPeriod); AppendStringElement(xmlDocStrategy, "sameDirSignalAction", strategy.SameSignalAction.ToString()); AppendStringElement(xmlDocStrategy, "oppDirSignalAction", strategy.OppSignalAction.ToString()); // Add the Permanent Stop Loss XmlElement newElem = xmlDocStrategy.CreateElement("permanentStopLoss"); newElem.InnerText = strategy.PermanentSL.ToString(CultureInfo.InvariantCulture); newElem.SetAttribute("usePermanentSL", strategy.UsePermanentSL.ToString(CultureInfo.InvariantCulture)); newElem.SetAttribute("permanentSLType", strategy.PermanentSLType.ToString()); if (xmlDocStrategy.DocumentElement != null) { xmlDocStrategy.DocumentElement.AppendChild(newElem); } // Add the Permanent Take Profit newElem = xmlDocStrategy.CreateElement("permanentTakeProfit"); newElem.InnerText = strategy.PermanentTP.ToString(CultureInfo.InvariantCulture); newElem.SetAttribute("usePermanentTP", strategy.UsePermanentTP.ToString(CultureInfo.InvariantCulture)); newElem.SetAttribute("permanentTPType", strategy.PermanentTPType.ToString()); if (xmlDocStrategy.DocumentElement != null) { xmlDocStrategy.DocumentElement.AppendChild(newElem); } // Add the Break Even newElem = xmlDocStrategy.CreateElement("breakEven"); newElem.InnerText = strategy.BreakEven.ToString(CultureInfo.InvariantCulture); newElem.SetAttribute("useBreakEven", strategy.UseBreakEven.ToString(CultureInfo.InvariantCulture)); if (xmlDocStrategy.DocumentElement != null) { xmlDocStrategy.DocumentElement.AppendChild(newElem); } AppendStringElement(xmlDocStrategy, "maxOpenLots", strategy.MaxOpenLots); AppendStringElement(xmlDocStrategy, "useAccountPercentEntry", strategy.UseAccountPercentEntry); AppendStringElement(xmlDocStrategy, "entryLots", strategy.EntryLots); AppendStringElement(xmlDocStrategy, "addingLots", strategy.AddingLots); AppendStringElement(xmlDocStrategy, "reducingLots", strategy.ReducingLots); AppendStringElement(xmlDocStrategy, "useMartingale", strategy.UseMartingale); AppendStringElement(xmlDocStrategy, "martingaleMultiplier", strategy.MartingaleMultiplier); AppendStringElement(xmlDocStrategy, "description", strategy.Description); // Add the slots. AppendStringElement(xmlDocStrategy, "openFilters", strategy.OpenFilters); AppendStringElement(xmlDocStrategy, "closeFilters", strategy.CloseFilters); for (int slot = 0; slot < strategy.Slots; slot++) { IndicatorSlot stratSlot = strategy.Slot[slot]; SlotTypes slType = stratSlot.SlotType; // Add a slot element. XmlElement newSlot = xmlDocStrategy.CreateElement("slot"); newSlot.SetAttribute("slotNumber", slot.ToString(CultureInfo.InvariantCulture)); newSlot.SetAttribute("slotType", slType.ToString()); newSlot.SetAttribute("slotStatus", stratSlot.SlotStatus.ToString()); if (slType == SlotTypes.OpenFilter || slType == SlotTypes.CloseFilter) { newSlot.SetAttribute("logicalGroup", stratSlot.LogicalGroup); } // Add an element. newElem = xmlDocStrategy.CreateElement("indicatorName"); newElem.InnerText = stratSlot.IndicatorName; newSlot.AppendChild(newElem); // Add the list parameters. for (int param = 0; param < stratSlot.IndParam.ListParam.Length; param++) { if (!stratSlot.IndParam.ListParam[param].Enabled) { continue; } // Add an element. XmlElement newListElem = xmlDocStrategy.CreateElement("listParam"); newListElem.SetAttribute("paramNumber", param.ToString(CultureInfo.InvariantCulture)); // Add an element. newElem = xmlDocStrategy.CreateElement("caption"); newElem.InnerText = stratSlot.IndParam.ListParam[param].Caption; newListElem.AppendChild(newElem); // Add an element. newElem = xmlDocStrategy.CreateElement("index"); newElem.InnerText = stratSlot.IndParam.ListParam[param].Index.ToString(CultureInfo.InvariantCulture); newListElem.AppendChild(newElem); // Add an element. newElem = xmlDocStrategy.CreateElement("value"); newElem.InnerText = stratSlot.IndParam.ListParam[param].Text; newListElem.AppendChild(newElem); newSlot.AppendChild(newListElem); } // Add the num parameters. for (int param = 0; param < stratSlot.IndParam.NumParam.Length; param++) { if (!stratSlot.IndParam.NumParam[param].Enabled) { continue; } // Add an element. XmlElement newNumElem = xmlDocStrategy.CreateElement("numParam"); newNumElem.SetAttribute("paramNumber", param.ToString(CultureInfo.InvariantCulture)); // Add an element. newElem = xmlDocStrategy.CreateElement("caption"); newElem.InnerText = stratSlot.IndParam.NumParam[param].Caption; newNumElem.AppendChild(newElem); // Add an element. newElem = xmlDocStrategy.CreateElement("value"); newElem.InnerText = stratSlot.IndParam.NumParam[param].ValueToString; newNumElem.AppendChild(newElem); newSlot.AppendChild(newNumElem); } // Add the check parameters. for (int param = 0; param < stratSlot.IndParam.CheckParam.Length; param++) { if (!stratSlot.IndParam.CheckParam[param].Enabled) { continue; } // Add an element. XmlElement newCheckElem = xmlDocStrategy.CreateElement("checkParam"); newCheckElem.SetAttribute("paramNumber", param.ToString(CultureInfo.InvariantCulture)); // Add an element. newElem = xmlDocStrategy.CreateElement("caption"); newElem.InnerText = stratSlot.IndParam.CheckParam[param].Caption; newCheckElem.AppendChild(newElem); // Add an element. newElem = xmlDocStrategy.CreateElement("value"); newElem.InnerText = stratSlot.IndParam.CheckParam[param].Checked.ToString(CultureInfo.InvariantCulture); newCheckElem.AppendChild(newElem); newSlot.AppendChild(newCheckElem); } if (xmlDocStrategy.DocumentElement != null) { xmlDocStrategy.DocumentElement.AppendChild(newSlot); } } // Add statistics meta data. string unit = " " + Configs.AccountCurrency; AppendStringElement(xmlDocStrategy, "AccountBalance", Backtester.NetMoneyBalance.ToString("F2") + unit); AppendStringElement(xmlDocStrategy, "ProfitPerDay", Backtester.MoneyProfitPerDay.ToString("F2") + unit); AppendStringElement(xmlDocStrategy, "WinLossRatio", Backtester.WinLossRatio.ToString("F2")); AppendStringElement(xmlDocStrategy, "AccountStatsParam", String.Join(";", Backtester.AccountStatsParam)); AppendStringElement(xmlDocStrategy, "AccountStatsValue", String.Join(";", Backtester.AccountStatsValue)); AppendStringElement(xmlDocStrategy, "MarketStatsParam", String.Join(";", Data.MarketStatsParam)); AppendStringElement(xmlDocStrategy, "MarketStatsValue", String.Join(";", Data.MarketStatsValue)); // Add chart data int length = Data.Bars - StatsBuffer.FirstBar; var balanceLine = new double[length]; var equityLine = new double[length]; for (int bar = 0; bar < length; bar++) { balanceLine[bar] = Backtester.MoneyBalance(bar); equityLine[bar] = Backtester.MoneyEquity(bar); } int size = Math.Min(600, length); string[] balanceList = MathUtils.ArrayToStringArray(MathUtils.ArrayResize(balanceLine, size)); string[] equityList = MathUtils.ArrayToStringArray(MathUtils.ArrayResize(equityLine, size)); AppendStringElement(xmlDocStrategy, "BalanceLine", String.Join(";", balanceList)); AppendStringElement(xmlDocStrategy, "EquityLine", String.Join(";", equityList)); return(xmlDocStrategy); }
/// <summary> /// Exports the positions info /// </summary> public void ExportPositions(bool showTransfers) { string stage = String.Empty; if (Data.IsProgramBeta) { stage = " " + Language.T("Beta"); } else if (Data.IsProgramReleaseCandidate) { stage = " " + "RC"; } string ff = Data.Ff; // Format modifier to print float numbers var sb = new StringBuilder(); sb.Append("Forex Strategy Builder v" + Data.ProgramVersion + stage + Environment.NewLine); sb.Append("Strategy name: " + Data.Strategy.StrategyName + Environment.NewLine); sb.Append("Exported on " + DateTime.Now + Environment.NewLine); sb.Append(Data.Symbol + " " + Data.PeriodString + "; Values in points" + Environment.NewLine); sb.Append("Pos Numb\t"); sb.Append("Bar Numb\t"); sb.Append("Bar Opening Time\t"); sb.Append("Direction\t"); sb.Append("Lots\t"); sb.Append("Transaction\t"); sb.Append("Order Price\t"); sb.Append("Average Price\t"); sb.Append("Profit Loss\t"); sb.Append("Floating P/L\t"); sb.Append("Balance\t"); sb.Append("Equity\t"); sb.Append(Environment.NewLine); for (int iPos = 0; iPos < Backtester.PositionsTotal; iPos++) { Position position = Backtester.PosFromNumb(iPos); int bar = Backtester.PosCoordinates[iPos].Bar; if (!showTransfers && position.Transaction == Transaction.Transfer) { continue; } sb.Append((position.PosNumb + 1) + "\t"); sb.Append((bar + 1) + "\t"); sb.Append(Data.Time[bar] + "\t"); sb.Append(position.PosDir + "\t"); sb.Append(position.PosLots + "\t"); sb.Append(position.Transaction + "\t"); sb.Append(position.FormOrdPrice.ToString(ff) + "\t"); sb.Append(position.PosPrice.ToString(ff) + "\t"); sb.Append(Math.Round(position.ProfitLoss) + "\t"); sb.Append(Math.Round(position.FloatingPL) + "\t"); sb.Append(Math.Round(position.Balance) + "\t"); sb.Append(Math.Round(position.Equity) + "\t"); sb.Append(Environment.NewLine); } string fileName = Data.Strategy.StrategyName + "-" + Data.Symbol + "-" + Data.Period; SaveData(fileName, sb); }
/// <summary> /// Paints panel pnlInfo /// </summary> private void PnlInfoPaint(object sender, PaintEventArgs e) { // ---------------------------------------------------------------------+ // | Way points description | // |--------------------------------------------------------------------+ // | Number | Description | Price | Direction | Lots | Position | Order | // |--------------------------------------------------------------------+ //xp0 xp1 xp2 xp3 xp4 xp5 xp6 xp7 Graphics g = e.Graphics; g.Clear(LayoutColors.ColorControlBack); if (!Data.IsData || !Data.IsResult) { return; } var pnl = (Panel)sender; string ff = Data.Ff; // Format modifier to print the floats var size = new Size(aiX[columns] - aiX[0], infoRowHeight); var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Near }; // Caption background var pntStart = new PointF(0, 0); SizeF szfCaption = new Size(pnl.ClientSize.Width, 2 * infoRowHeight); var rectCaption = new RectangleF(pntStart, szfCaption); Data.GradientPaint(g, rectCaption, LayoutColors.ColorCaptionBack, LayoutColors.DepthCaption); // Caption Text var stringFormat = new StringFormat { LineAlignment = StringAlignment.Center, Trimming = StringTrimming.EllipsisCharacter, FormatFlags = StringFormatFlags.NoWrap, Alignment = StringAlignment.Near }; string stringCaptionText = Language.T("Way Points Description"); float captionWidth = Math.Min(pnlInfo.ClientSize.Width, aiX[columns] - aiX[0]); float fCaptionTextWidth = g.MeasureString(stringCaptionText, fontInfo).Width; float fCaptionTextX = Math.Max((captionWidth - fCaptionTextWidth) / 2f, 0); var pfCaptionText = new PointF(fCaptionTextX, 0); var sfCaptionText = new SizeF(captionWidth - fCaptionTextX, infoRowHeight); rectCaption = new RectangleF(pfCaptionText, sfCaptionText); // First caption raw g.DrawString(stringCaptionText, fontInfo, brushCaptionText, rectCaption, stringFormat); // Second caption raw for (int i = 0; i < columns; i++) { g.DrawString(asTitles[i], fontInfo, brushCaptionText, (aiX[i] + aiX[i + 1]) / 2f, infoRowHeight, sf); } Brush brush = new SolidBrush(LayoutColors.ColorControlText); for (int pnt = 0; pnt < Backtester.WayPoints(barCurrent); pnt++) { int y = (pnt + 2) * infoRowHeight; var point = new Point(aiX[0], y); // Even row if (Math.Abs(pnt % 2f - 0) > 0.00001) { g.FillRectangle(brushEvenRow, new Rectangle(point, size)); } int positionNumber = Backtester.WayPoint(barCurrent, pnt).PosNumb; WayPointType wpType = Backtester.WayPoint(barCurrent, pnt).WpType; PosDirection posDirection = Backtester.PosFromNumb(positionNumber).PosDir; double posLots = Backtester.PosFromNumb(positionNumber).PosLots; int ordNumber = Backtester.WayPoint(barCurrent, pnt).OrdNumb; g.DrawString((pnt + 1).ToString(CultureInfo.InvariantCulture), fontInfo, brush, (aiX[0] + aiX[1]) / 2f, y, sf); g.DrawString(Language.T(WayPoint.WpTypeToString(wpType)), fontInfo, brush, aiX[1] + 2, y); g.DrawString(Backtester.WayPoint(barCurrent, pnt).Price.ToString(ff), fontInfo, brush, (aiX[3] + aiX[2]) / 2f, y, sf); if (positionNumber > -1) { g.DrawString(Language.T(posDirection.ToString()), fontInfo, brush, (aiX[4] + aiX[3]) / 2f, y, sf); g.DrawString(posLots.ToString(CultureInfo.InvariantCulture), fontInfo, brush, (aiX[5] + aiX[4]) / 2f, y, sf); g.DrawString((positionNumber + 1).ToString(CultureInfo.InvariantCulture), fontInfo, brush, (aiX[6] + aiX[5]) / 2f, y, sf); } if (ordNumber > -1) { g.DrawString((ordNumber + 1).ToString(CultureInfo.InvariantCulture), fontInfo, brush, (aiX[7] + aiX[6]) / 2f, y, sf); } } // Vertical lines var penLine = new Pen(LayoutColors.ColorJournalLines); for (int i = 1; i < columns; i++) { g.DrawLine(penLine, aiX[i], 2 * infoRowHeight, aiX[i], ClientSize.Height - Border); } // Border var penBorder = new Pen(Data.GetGradientColor(LayoutColors.ColorCaptionBack, -LayoutColors.DepthCaption), Border); g.DrawLine(penBorder, 1, 2 * infoRowHeight, 1, pnl.ClientSize.Height); g.DrawLine(penBorder, pnl.ClientSize.Width - Border + 1, 2 * infoRowHeight, pnl.ClientSize.Width - Border + 1, pnl.ClientSize.Height); g.DrawLine(penBorder, 0, pnl.ClientSize.Height - Border + 1, pnl.ClientSize.Width, pnl.ClientSize.Height - Border + 1); }
/// <summary> /// Sets chart's back testing data. /// </summary> public void SetChartData() { isNotPaint = !Data.IsData || !Data.IsResult || Data.Bars <= Data.FirstBar; if (isNotPaint) { return; } showPriceLine = Configs.ShowPriceChartOnAccountChart && Backtester.ExecutedOrders > 0; isScanPerformed = Backtester.IsScanPerformed; data.FirstBar = Data.FirstBar; data.Bars = Data.Bars; chartBars = Data.Bars - Data.FirstBar; int maxBalance = Configs.AccountInMoney ? (int)Backtester.MaxMoneyBalance : Backtester.MaxBalance; int minBalance = Configs.AccountInMoney ? (int)Backtester.MinMoneyBalance : Backtester.MinBalance; int maxEquity = Configs.AccountInMoney ? (int)Backtester.MaxMoneyEquity : Backtester.MaxEquity; int minEquity = Configs.AccountInMoney ? (int)Backtester.MinMoneyEquity : Backtester.MinEquity; if (Configs.AdditionalStatistics) { int maxLongBalance = Configs.AccountInMoney ? (int)Backtester.MaxLongMoneyBalance : Backtester.MaxLongBalance; int minLongBalance = Configs.AccountInMoney ? (int)Backtester.MinLongMoneyBalance : Backtester.MinLongBalance; int maxShortBalance = Configs.AccountInMoney ? (int)Backtester.MaxShortMoneyBalance : Backtester.MaxShortBalance; int minShortBalance = Configs.AccountInMoney ? (int)Backtester.MinShortMoneyBalance : Backtester.MinShortBalance; int maxLongShortBalance = Math.Max(maxLongBalance, maxShortBalance); int minLongShortBalance = Math.Min(minLongBalance, minShortBalance); data.Maximum = Math.Max(Math.Max(maxBalance, maxEquity), maxLongShortBalance) + 1; data.Minimum = Math.Min(Math.Min(minBalance, minEquity), minLongShortBalance) - 1; } else { data.Maximum = Math.Max(maxBalance, maxEquity) + 1; data.Minimum = Math.Min(minBalance, minEquity) - 1; } data.Minimum = (int)(Math.Floor(data.Minimum / 10f) * 10); data.DataMaxPrice = Data.MaxPrice; data.DataMinPrice = Data.MinPrice; if (showPriceLine) { data.ClosePrice = new double[data.Bars]; Data.Close.CopyTo(data.ClosePrice, 0); } if (Configs.AccountInMoney) { data.MoneyBalance = new double[data.Bars]; data.MoneyEquity = new double[data.Bars]; } else { data.Balance = new int[data.Bars]; data.Equity = new int[data.Bars]; } if (Configs.AdditionalStatistics) { if (Configs.AccountInMoney) { data.LongMoneyBalance = new double[data.Bars]; data.ShortMoneyBalance = new double[data.Bars]; } else { data.LongBalance = new int[data.Bars]; data.ShortBalance = new int[data.Bars]; } } for (int bar = data.FirstBar; bar < data.Bars; bar++) { if (Configs.AccountInMoney) { data.MoneyBalance[bar] = Backtester.MoneyBalance(bar); data.MoneyEquity[bar] = Backtester.MoneyEquity(bar); } else { data.Balance[bar] = Backtester.Balance(bar); data.Equity[bar] = Backtester.Equity(bar); } if (Configs.AdditionalStatistics) { if (Configs.AccountInMoney) { data.LongMoneyBalance[bar] = Backtester.LongMoneyBalance(bar); data.ShortMoneyBalance[bar] = Backtester.ShortMoneyBalance(bar); } else { data.LongBalance[bar] = Backtester.LongBalance(bar); data.ShortBalance[bar] = Backtester.ShortBalance(bar); } } } data.MarginCallBar = Backtester.MarginCallBar; if (IsOOS && OOSBar > data.FirstBar) { data.NetBalance = (float)(Configs.AccountInMoney ? Backtester.MoneyBalance(OOSBar) : Backtester.Balance(OOSBar)); data.DataTimeBarOOS = Data.Time[OOSBar]; } else { data.NetBalance = (float)(Configs.AccountInMoney ? Backtester.NetMoneyBalance : Backtester.NetBalance); } }
/// <summary> /// Exports the bar summary /// </summary> public void ExportBarSummary() { string stage = String.Empty; if (Data.IsProgramBeta) { stage = " " + Language.T("Beta"); } else if (Data.IsProgramReleaseCandidate) { stage = " " + "RC"; } string ff = Data.Ff; // Format modifier to print float numbers string df = Data.Df; // Format modifier to print date var sb = new StringBuilder(); sb.Append("Forex Strategy Builder v" + Data.ProgramVersion + stage + Environment.NewLine); sb.Append("Strategy name: " + Data.Strategy.StrategyName + Environment.NewLine); sb.Append("Exported on " + DateTime.Now + Environment.NewLine); sb.Append(Data.Symbol + " " + Data.PeriodString + "; Values in points" + Environment.NewLine); sb.Append("Bar Numb\t"); sb.Append("Date\t"); sb.Append("Hour\t"); sb.Append("Open\t"); sb.Append("High\t"); sb.Append("Low\t"); sb.Append("Close\t"); sb.Append("Volume\t"); sb.Append("Direction\t"); sb.Append("Lots\t"); sb.Append("Transaction\t"); sb.Append("Price\t"); sb.Append("Profit Loss\t"); sb.Append("Floating P/L\t"); sb.Append("Spread\t"); sb.Append("Rollover\t"); sb.Append("Balance\t"); sb.Append("Equity\t"); sb.Append("Interpolation" + Environment.NewLine); for (int bar = 0; bar < Data.Bars; bar++) { sb.Append((bar + 1) + "\t"); sb.Append(Data.Time[bar].ToString(df) + "\t"); sb.Append(Data.Time[bar].ToString("HH:mm") + "\t"); sb.Append(Data.Open[bar].ToString(ff) + "\t"); sb.Append(Data.High[bar].ToString(ff) + "\t"); sb.Append(Data.Low[bar].ToString(ff) + "\t"); sb.Append(Data.Close[bar].ToString(ff) + "\t"); sb.Append(Data.Volume[bar] + "\t"); if (Backtester.IsPos(bar)) { sb.Append(Backtester.SummaryDir(bar) + "\t"); sb.Append(Backtester.SummaryLots(bar) + "\t"); sb.Append(Backtester.SummaryTrans(bar) + "\t"); sb.Append(Backtester.SummaryPrice(bar).ToString(ff) + "\t"); sb.Append(Backtester.ProfitLoss(bar) + "\t"); sb.Append(Backtester.FloatingPL(bar) + "\t"); } else { sb.Append("\t\t\t\t\t\t"); } sb.Append(Backtester.ChargedSpread(bar) + "\t"); sb.Append(Backtester.ChargedRollOver(bar) + "\t"); sb.Append(Backtester.Balance(bar) + "\t"); sb.Append(Backtester.Equity(bar) + "\t"); sb.Append(Backtester.BackTestEvalToString(bar) + "\t"); sb.Append(Environment.NewLine); } string fileName = Data.Strategy.StrategyName + "-" + Data.Symbol + "-" + Data.Period.ToString(); SaveData(fileName, sb); }
/// <summary> /// Navigates to a bar. /// </summary> private void Navigate(string sDir) { switch (sDir) { case "< !": for (int i = barCurrent - 1; i >= Data.FirstBar; i--) { if (Backtester.BackTestEval(i) == BacktestEval.Ambiguous) { barCurrent = i; break; } } break; case "! >": for (int i = barCurrent + 1; i < Data.Bars; i++) { if (Backtester.BackTestEval(i) == BacktestEval.Ambiguous) { barCurrent = i; break; } } break; case "<<": for (int i = barCurrent - 1; i >= Data.FirstBar; i--) { if (Backtester.SummaryTrans(i) != Transaction.Transfer && Backtester.SummaryTrans(i) != Transaction.None) { barCurrent = i; break; } } break; case ">>": for (int i = barCurrent + 1; i < Data.Bars; i++) { if (Backtester.SummaryTrans(i) != Transaction.Transfer && Backtester.SummaryTrans(i) != Transaction.None) { barCurrent = i; break; } } break; case "<max": int maxWp = 0; int maxBar = barCurrent; for (int i = barCurrent - 1; i >= Data.FirstBar; i--) { if (Backtester.WayPoints(i) > maxWp) { maxWp = Backtester.WayPoints(i); maxBar = i; } } barCurrent = maxBar; break; case ">max": maxWp = 0; maxBar = barCurrent; for (int i = barCurrent + 1; i < Data.Bars; i++) { if (Backtester.WayPoints(i) > maxWp) { maxWp = Backtester.WayPoints(i); maxBar = i; } } barCurrent = maxBar; break; case "<": if (barCurrent > Data.FirstBar) { barCurrent--; } break; case ">": if (barCurrent < Data.Bars - 1) { barCurrent++; } break; case "Go": barCurrent = (int)nudGo.Value - 1; break; } SetBtnNavigate(); barInfo = Language.T("Bar") + ": " + (barCurrent + 1) + " " + Data.Time[barCurrent].ToString(Data.Df) + " " + Data.Time[barCurrent].ToString("HH:mm") + "; " + Language.T("Interpolation method") + ": " + Backtester.InterpolationMethodToString(); var rectPnlChart = new Rectangle(Border, infoRowHeight, pnlChart.ClientSize.Width - 2 * Border, pnlChart.ClientSize.Height - infoRowHeight - Border); pnlChart.Invalidate(rectPnlChart); var rectPnlInfo = new Rectangle(Border, 2 * infoRowHeight, pnlInfo.ClientSize.Width - 2 * Border, pnlInfo.ClientSize.Height - 2 * infoRowHeight - Border); pnlInfo.Invalidate(rectPnlInfo); nudGo.Value = barCurrent + 1; }
/// <summary> /// Exports the positions info in currency /// </summary> public void ExportPositionsInMoney(bool showTransfers) { string stage = String.Empty; if (Data.IsProgramBeta) { stage = " " + Language.T("Beta"); } else if (Data.IsProgramReleaseCandidate) { stage = " " + "RC"; } string ff = Data.Ff; // Format modifier to print float numbers var sb = new StringBuilder(); sb.Append("Forex Strategy Builder v" + Data.ProgramVersion + stage + Environment.NewLine); sb.Append("Strategy name: " + Data.Strategy.StrategyName + Environment.NewLine); sb.Append("Exported on " + DateTime.Now + Environment.NewLine); sb.Append(Data.Symbol + " " + Data.PeriodString + "; Values in " + Configs.AccountCurrency + Environment.NewLine); sb.Append("Pos Numb\t"); sb.Append("Bar Numb\t"); sb.Append("Bar Opening Time\t"); sb.Append("Direction\t"); sb.Append("Amount\t"); sb.Append("Transaction\t"); sb.Append("Order Price\t"); sb.Append("Price\t"); sb.Append("Profit Loss\t"); sb.Append("Floating P/L\t"); sb.Append("Balance\t"); sb.Append("Equity\t"); sb.Append(Environment.NewLine); for (int pos = 0; pos < Backtester.PositionsTotal; pos++) { Position position = Backtester.PosFromNumb(pos); int bar = Backtester.PosCoordinates[pos].Bar; if (!showTransfers && position.Transaction == Transaction.Transfer) { continue; } sb.Append((position.PosNumb + 1) + "\t"); sb.Append((bar + 1) + "\t"); sb.Append(Data.Time[bar] + "\t"); sb.Append(position.PosDir + "\t"); sb.Append((position.PosDir == PosDirection.Long ? "" : "-") + (position.PosLots * Data.InstrProperties.LotSize) + "\t"); sb.Append(position.Transaction + "\t"); sb.Append(position.FormOrdPrice.ToString(ff) + "\t"); sb.Append(position.PosPrice.ToString(ff) + "\t"); sb.Append(position.MoneyProfitLoss.ToString("F2") + "\t"); sb.Append(position.MoneyFloatingPL.ToString("F2") + "\t"); sb.Append(position.MoneyBalance.ToString("F2") + "\t"); sb.Append(position.MoneyEquity.ToString("F2") + "\t"); sb.Append(Environment.NewLine); } string fileName = Data.Strategy.StrategyName + "-" + Data.Symbol + "-" + Data.Period; SaveData(fileName, sb); }
private void CalculateStrategy() { Backtester.Calculate(); Backtester.CalculateAccountStats(); }