/// <summary> /// Resets parameters and recalculates the strategy. /// </summary> private void ResetStrategyParameters() { for (int param = 0; param < parameters; param++) { int point = aParameter[param].Point; string stringFormat = "{0:F" + point + "}"; double value = initialValues[param]; aParameter[param].Value = value; alblParameterValue[param].Text = string.Format(stringFormat, value); } int lastSlot = -1; for (int param = 0; param < parameters; param++) { if (aParameter[param].Type != OptimizerParameterType.Indicator) { continue; } if (aParameter[param].SlotNumber == lastSlot) { continue; } lastSlot = aParameter[param].SlotNumber; CalculateIndicator(lastSlot); } Backtester.Calculate(); Backtester.CalculateAccountStats(); balanceChart.SetChartData(); balanceChart.InitChart(); balanceChart.Invalidate(); isStartegyChanged = false; }
/// <summary> /// This event handler deals with the results of the background operation /// </summary> void BgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (!e.Cancelled && Configs.PlaySounds) { System.Media.SystemSounds.Exclamation.Play(); } Backtester.Calculate(); Backtester.CalculateAccountStats(); string report = GenerateReport(); SaveReport(report); foreach (Control control in this.Controls) { control.Enabled = true; } btnStart.Enabled = true; btnStart.Text = Language.T("Start"); Cursor = Cursors.Default; isRunning = false; return; }
private void CalculateStrategy() { foreach (IndicatorSlot indSlot in Data.Strategy.Slot) { string indicatorName = indSlot.IndicatorName; SlotTypes slotType = indSlot.SlotType; Indicator indicator = IndicatorManager.ConstructIndicator(indicatorName); indicator.Initialize(slotType); indicator.IndParam = indSlot.IndParam; indicator.Calculate(Data.DataSet); indSlot.IndicatorName = indicator.IndicatorName; indSlot.IndParam = indicator.IndParam; indSlot.Component = indicator.Component; indSlot.SeparatedChart = indicator.SeparatedChart; indSlot.SpecValue = indicator.SpecialValues; indSlot.MinValue = indicator.SeparatedChartMinValue; indSlot.MaxValue = indicator.SeparatedChartMaxValue; indSlot.IsDefined = true; } Data.FirstBar = Data.Strategy.SetFirstBar(); Backtester.Calculate(); Backtester.CalculateAccountStats(); Data.IsResult = true; StatsBuffer.UpdateStatsBuffer(); }
/// <summary> /// Constructor /// </summary> public WayPoint(double price, WayPointType wpType, int ordNumb, int posNumb) { Price = price; WpType = wpType; if (wpType == WayPointType.Open || wpType == WayPointType.High || wpType == WayPointType.Low || wpType == WayPointType.Close || wpType == WayPointType.None) { OrdNumb = -1; } else { OrdNumb = ordNumb; } if (Backtester.PosFromNumb(posNumb).PosDir == PosDirection.None || Backtester.PosFromNumb(posNumb).PosDir == PosDirection.Closed && wpType != WayPointType.Exit && wpType != WayPointType.Reduce) { PosNumb = -1; } else { PosNumb = posNumb; } }
/// <summary> /// Forces the buffer to collect data. /// </summary> public static void UpdateStatsBuffer() { Strategy = Data.Strategy.Clone(); PositionsTotal = Backtester.PositionsTotal; _session = Backtester.GetAllSessionsCopy(); _posCoord = Backtester.GetPosCoordinateCopy(); _ordCoord = Backtester.GetOrdCoordinateCopy(); }
/// <summary> /// This event handler deals with the results of the background operation. /// </summary> private void BgWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { Backtester.Calculate(); Backtester.CalculateAccountStats(); BalanceChart.SetChartData(); BalanceChart.InitChart(); BalanceChart.Invalidate(); if (!e.Cancelled && Configs.PlaySounds) { SystemSounds.Exclamation.Play(); } _isOptimizing = false; BtnCancel.Enabled = true; BtnAccept.Enabled = true; BtnOptimize.Text = Language.T("Optimize"); ProgressBar.Value = 1; if (PnlParams.Visible) { for (int i = 0; i <= (int)OptimizerButtons.ResetStrategy; i++) { AOptimizerButtons[i].Enabled = true; } } for (int i = 0; i < _parameters; i++) { AlblParameterValue[i].Text = GetParameterText(i); } foreach (Control control in PnlParams.Controls) { control.Enabled = true; } foreach (Control control in PnlLimitations.Controls) { control.Enabled = true; } foreach (Control control in PnlSettings.Controls) { control.Enabled = true; } if (ChbOptimizerWritesReport.Checked) { SaveReport(); } Cursor = Cursors.Default; }
/// <summary> /// Prepare the strategy for generating /// </summary> private void PrepareStrategyForGenerating() { _lockedEntrySlot = null; _lockedEntryFilters = 0; _aLockedEntryFilter = new IndicatorSlot[Math.Max(Strategy.MaxOpenFilters, _strategyBest.OpenFilters)]; _lockedExitSlot = null; _lockedExitFilters = 0; _aLockedExitFilter = new IndicatorSlot[Math.Max(Strategy.MaxCloseFilters, _strategyBest.CloseFilters)]; // Copy the locked slots for (int slot = 0; slot < _strategyBest.Slots; slot++) { if (_strategyBest.Slot[slot].SlotStatus == StrategySlotStatus.Locked || _strategyBest.Slot[slot].SlotStatus == StrategySlotStatus.Linked) { if (_strategyBest.Slot[slot].SlotType == SlotTypes.Open) { _lockedEntrySlot = _strategyBest.Slot[slot]; } else if (_strategyBest.Slot[slot].SlotType == SlotTypes.OpenFilter) { _aLockedEntryFilter[_lockedEntryFilters] = _strategyBest.Slot[slot]; _lockedEntryFilters++; } else if (_strategyBest.Slot[slot].SlotType == SlotTypes.Close) { _lockedExitSlot = _strategyBest.Slot[slot]; } else if (_strategyBest.Slot[slot].SlotType == SlotTypes.CloseFilter) { _aLockedExitFilter[_lockedExitFilters] = _strategyBest.Slot[slot]; _lockedExitFilters++; } } } if (ChbGenerateNewStrategy.Checked) { _bestBalance = 0; } else { _bestBalance = (_isOOS ? Backtester.Balance(_barOOS) : Backtester.NetBalance); } _maxOpeningLogicSlots = ChbMaxOpeningLogicSlots.Checked ? (int)NUDMaxOpeningLogicSlots.Value : Strategy.MaxOpenFilters; _maxClosingLogicSlots = ChbMaxClosingLogicSlots.Checked ? (int)NUDMaxClosingLogicSlots.Value : Strategy.MaxCloseFilters; }
/// <summary> /// This event handler deals with the results of the background operation /// </summary> void BgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (!e.Cancelled && Configs.PlaySounds) { System.Media.SystemSounds.Exclamation.Play(); } RestoreFromBest(); Backtester.Calculate(); Backtester.CalculateAccountStats(); smallBalanceChart.SetChartData(); smallBalanceChart.InitChart(); smallBalanceChart.Invalidate(); strategyLayout.Enabled = true; RebuildStrategyLayout(strategyBest); isGenerating = false; btnAccept.Enabled = true; btnCancel.Enabled = true; foreach (Control control in pnlCommon.Controls) { control.Enabled = true; } foreach (Control control in pnlLimitations.Controls) { control.Enabled = true; } foreach (Control control in pnlSettings.Controls) { control.Enabled = true; } indicatorsLayout.UnblockIndikatorChange(); tsbtLockAll.Enabled = true; tsbtUnlockAll.Enabled = true; tsbtLinkAll.Enabled = true; tsbtOverview.Enabled = true; tsbtStrategyInfo.Enabled = true; btnGenerate.Text = Language.T("Generate"); progressBar.Style = ProgressBarStyle.Blocks; Cursor = Cursors.Default; return; }
/// <summary> /// Prepare the strategy for generating /// </summary> void PrepareStrategyForGenerating() { lockedEntrySlot = null; lockedEntryFilters = 0; aLockedEntryFilter = new IndicatorSlot[Math.Max(Strategy.MaxOpenFilters, strategyBest.OpenFilters)]; lockedExitSlot = null; lockedExitFilters = 0; aLockedExitFilter = new IndicatorSlot[Math.Max(Strategy.MaxCloseFilters, strategyBest.CloseFilters)]; // Copy the locked slots for (int slot = 0; slot < strategyBest.Slots; slot++) { if (strategyBest.Slot[slot].SlotStatus == StrategySlotStatus.Locked || strategyBest.Slot[slot].SlotStatus == StrategySlotStatus.Linked) { if (strategyBest.Slot[slot].SlotType == SlotTypes.Open) { lockedEntrySlot = strategyBest.Slot[slot]; } else if (strategyBest.Slot[slot].SlotType == SlotTypes.OpenFilter) { aLockedEntryFilter[lockedEntryFilters] = strategyBest.Slot[slot]; lockedEntryFilters++; } else if (strategyBest.Slot[slot].SlotType == SlotTypes.Close) { lockedExitSlot = strategyBest.Slot[slot]; } else if (strategyBest.Slot[slot].SlotType == SlotTypes.CloseFilter) { aLockedExitFilter[lockedExitFilters] = strategyBest.Slot[slot]; lockedExitFilters++; } } } if (chbGenerateNewStrategy.Checked) { bestBalance = 0; } else { bestBalance = (isOOS ? Backtester.Balance(barOOS) : Backtester.NetBalance); } maxOpeningLogicSlots = chbMaxOpeningLogicSlots.Checked ? (int)nudMaxOpeningLogicSlots.Value: Strategy.MaxOpenFilters; maxClosingLogicSlots = chbMaxClosingLogicSlots.Checked ? (int)nudMaxClosingLogicSlots.Value: Strategy.MaxCloseFilters; return; }
/// <summary> /// Calculates Data Tables. /// </summary> void CalculateStatsTables(int percentDeviation, int countParam) { string unit = " " + Configs.AccountCurrency; string[] tableNames = new string[] { Language.T("Account balance") + unit, Language.T("Profit per day") + unit, Language.T("Maximum drawdown") + unit, Language.T("Gross profit") + unit, Language.T("Gross loss") + unit, Language.T("Executed orders"), Language.T("Traded lots"), Language.T("Time in position") + " %", Language.T("Sent orders"), Language.T("Charged spread") + unit, Language.T("Charged rollover") + unit, Language.T("Winning trades"), Language.T("Losing trades"), Language.T("Win/loss ratio"), Language.T("Max equity drawdown") + " %" }; tablesCount = tableNames.Length; tableReport = new Over_optimization_Data_Table[tablesCount]; for (int t = 0; t < tableNames.Length; t++) { tableReport[t] = new Over_optimization_Data_Table(percentDeviation, countParam); tableReport[t].Name = tableNames[t]; } int parNumber = 0; bool isBGWorkCanceled = false; for (int slot = 0; slot < Data.Strategy.Slots && !isBGWorkCanceled; slot++) { for (int numParam = 0; numParam < 6 && !isBGWorkCanceled; numParam++) { if (Data.Strategy.Slot[slot].IndParam.NumParam[numParam].Enabled && parNumber < countParam) { for (int index = percentDeviation; index >= -percentDeviation && !isBGWorkCanceled; index--) { isBGWorkCanceled = bgWorker.CancellationPending; Data.Strategy.Slot[slot].IndParam.NumParam[numParam].Value = tableParameters.GetData(index, parNumber); CalculateIndicator(slot); Backtester.Calculate(); Backtester.CalculateAccountStats(); double[] statValues = new double[] { Backtester.NetMoneyBalance, Backtester.MoneyProfitPerDay, Backtester.MaxMoneyDrawdown, Backtester.GrossMoneyProfit, Backtester.GrossMoneyLoss, Backtester.ExecutedOrders, Backtester.TradedLots, Backtester.TimeInPosition, Backtester.SentOrders, Backtester.TotalChargedMoneySpread, Backtester.TotalChargedMoneyRollOver, Backtester.WinningTrades, Backtester.LosingTrades, Backtester.WinLossRatio, Backtester.MoneyEquityPercentDrawdown }; for (int tn = 0; tn < tablesCount; tn++) { tableReport[tn].SetData(index, parNumber, statValues[tn]); } // Report progress as a percentage of the total task. computedCycles++; int percentComplete = Math.Min(100 * computedCycles / cycles, 100); if (percentComplete > progressPercent) { progressPercent = percentComplete; bgWorker.ReportProgress(percentComplete); } } // Set default value Data.Strategy.Slot[slot].IndParam.NumParam[numParam].Value = tableParameters.GetData(0, parNumber); CalculateIndicator(slot); parNumber++; } } } }
/// <summary> /// Optimize all the checked parameters /// </summary> private void OptimizeParams(BackgroundWorker worker, DoWorkEventArgs e) { int bestBalance = (isOOS ? Backtester.Balance(barOOS) : Backtester.NetBalance); // First Optimization Cycle for (int round = 0; round < checkedParams && isOptimizing; round++) { if (worker.CancellationPending) { break; } int param = aiChecked[round]; var min = (double)anudParameterMin[param].Value; var max = (double)anudParameterMax[param].Value; var step = (double)anudParameterStep[param].Value; for (double value = min; value <= max; value += step) { if (worker.CancellationPending) { break; } aParameter[param].Value = value; if (aParameter[param].Type == OptimizerParameterType.Indicator) { CalculateIndicator(aParameter[param].SlotNumber); } Backtester.Calculate(); Backtester.CalculateAccountStats(); if (chbOptimizerWritesReport.Checked) { FillInReport(); } int balance = isOOS ? Backtester.Balance(barOOS) : Backtester.NetBalance; bool isCriteriaFulfilled = criteriaControls.IsCriteriaFulfilled(); if (balance > bestBalance && isCriteriaFulfilled) { bestBalance = balance; aParameter[param].BestValue = value; ShowParamBestValue(param); balanceChart.SetChartData(); balanceChart.InitChart(); balanceChart.Invalidate(); isStartegyChanged = true; SetStrategyToGeneratorHistory(); } // Report progress as a percentage of the total task. computedCycles++; int percentComplete = 100 * computedCycles / cycles; percentComplete = percentComplete > 100 ? 100 : percentComplete; if (percentComplete > progressPercent) { progressPercent = percentComplete; worker.ReportProgress(percentComplete); } } aParameter[param].Value = aParameter[param].BestValue; if (aParameter[param].Type == OptimizerParameterType.Indicator) { CalculateIndicator(aParameter[param].SlotNumber); } Backtester.Calculate(); Backtester.CalculateAccountStats(); } if (worker.CancellationPending) { e.Cancel = true; return; } if (checkedParams < 2) { return; } // Counts the necessary round int rounds = 0; for (int i = 0; i < checkedParams - 1; i++) { for (int j = 0; j < checkedParams; j++) { if (i < j) { rounds++; } } } var aCp = new CoupleOfParams[rounds]; var aCpTemp = new CoupleOfParams[rounds]; rounds = 0; for (int i = 0; i < checkedParams - 1; i++) { for (int j = 0; j < checkedParams; j++) { if (i < j) { aCpTemp[rounds].Param1 = aiChecked[i]; aCpTemp[rounds].Param2 = aiChecked[j]; aCpTemp[rounds].IsPassed = false; rounds++; } } } // Shaking the parameters for (int round = 0; round < rounds; round++) { int couple; do { couple = rand.Next(rounds); } while (aCpTemp[couple].IsPassed); aCpTemp[couple].IsPassed = true; aCp[round] = aCpTemp[couple]; } // The Optimization Cycle for (int round = 0; round < rounds; round++) { if (worker.CancellationPending) { break; } int param1 = aCp[round].Param1; int param2 = aCp[round].Param2; bool isOneIndicator = (aParameter[param1].Type == OptimizerParameterType.Indicator && aParameter[param2].Type == OptimizerParameterType.Indicator && aParameter[param1].IndParam.IndicatorName == aParameter[param2].IndParam.IndicatorName); var min1 = (double)anudParameterMin[param1].Value; var max1 = (double)anudParameterMax[param1].Value; var step1 = (double)anudParameterStep[param1].Value; var min2 = (double)anudParameterMin[param2].Value; var max2 = (double)anudParameterMax[param2].Value; var step2 = (double)anudParameterStep[param2].Value; for (double value1 = min1; value1 <= max1; value1 += step1) { if (worker.CancellationPending) { break; } if (!isOneIndicator) { aParameter[param1].Value = value1; if (aParameter[param1].Type == OptimizerParameterType.Indicator) { CalculateIndicator(aParameter[param1].SlotNumber); } } for (double value2 = min2; value2 <= max2; value2 += step2) { if (worker.CancellationPending) { break; } if (isOneIndicator) { aParameter[param1].Value = value1; aParameter[param2].Value = value2; if (aParameter[param1].Type == OptimizerParameterType.Indicator) { CalculateIndicator(aParameter[param1].SlotNumber); } } else { aParameter[param2].Value = value2; if (aParameter[param2].Type == OptimizerParameterType.Indicator) { CalculateIndicator(aParameter[param2].SlotNumber); } } // Calculates the Strategy Backtester.Calculate(); Backtester.CalculateAccountStats(); if (chbOptimizerWritesReport.Checked) { FillInReport(); } int balance = isOOS ? Backtester.Balance(barOOS) : Backtester.NetBalance; bool isCriteriaFulfilled = criteriaControls.IsCriteriaFulfilled(); if (balance > bestBalance && isCriteriaFulfilled) { bestBalance = balance; aParameter[param1].BestValue = value1; aParameter[param2].BestValue = value2; ShowParamBestValue(param1); ShowParamBestValue(param2); balanceChart.SetChartData(); balanceChart.InitChart(); balanceChart.Invalidate(); isStartegyChanged = true; SetStrategyToGeneratorHistory(); } // Report progress as a percentage of the total task. computedCycles++; int percentComplete = 100 * computedCycles / cycles; percentComplete = percentComplete > 100 ? 100 : percentComplete; if (percentComplete > progressPercent) { progressPercent = percentComplete; worker.ReportProgress(percentComplete); } } } aParameter[param1].Value = aParameter[param1].BestValue; aParameter[param2].Value = aParameter[param2].BestValue; if (isOneIndicator) { if (aParameter[param1].Type == OptimizerParameterType.Indicator) { CalculateIndicator(aParameter[param1].SlotNumber); } } else { if (aParameter[param1].Type == OptimizerParameterType.Indicator) { CalculateIndicator(aParameter[param1].SlotNumber); } if (aParameter[param2].Type == OptimizerParameterType.Indicator) { CalculateIndicator(aParameter[param2].SlotNumber); } } Backtester.Calculate(); Backtester.CalculateAccountStats(); } if (worker.CancellationPending) { e.Cancel = true; } }
/// <summary> /// This event handler deals with the results of the background operation. /// </summary> private void BgWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { Backtester.Calculate(); Backtester.CalculateAccountStats(); balanceChart.SetChartData(); balanceChart.InitChart(); balanceChart.Invalidate(); if (!e.Cancelled && Configs.PlaySounds) { SystemSounds.Exclamation.Play(); } isOptimizing = false; btnCancel.Enabled = true; btnAccept.Enabled = true; btnOptimize.Text = Language.T("Optimize"); progressBar.Value = 1; if (pnlParams.Visible) { for (int i = 0; i <= (int)OptimizerButtons.ResetStrategy; i++) { aOptimizerButtons[i].Enabled = true; } } for (int i = 0; i < parameters; i++) { alblParameterValue[i].Text = GetParameterText(i); } foreach (Control control in pnlParams.Controls) { control.Enabled = true; } foreach (Control control in criteriaControls.Controls) { control.Enabled = true; } foreach (Control control in pnlSettings.Controls) { control.Enabled = true; } if (chbOptimizerWritesReport.Checked) { SaveReport(); } Cursor = Cursors.Default; if (Data.AutoOptimize != "") { //Save strategy and exit double profit = Backtester.NetMoneyBalance - Configs.InitialAccount; String drawdown = Backtester.MoneyEquityPercentDrawdown.ToString("F2"); String filename = System.IO.Path.GetFileName(Data.AutoOptimize); //Create dir string subPath = "Optimized"; System.IO.Directory.CreateDirectory(subPath); //Save result to CSV System.IO.StreamWriter file = new System.IO.StreamWriter(subPath + "/results.csv", true); file.WriteLine(Data.Symbol + ";" + Data.PeriodString + ";" + Data.Strategy.EntryLots + ";" + filename + ";" + profit.ToString("F2") + ";" + drawdown); //balanceChart. file.Close(); //Autosave strategy Data.Strategy.Save(subPath + "/" + filename); Close(); } }
public bool IsCriteriaFulfilled() { // Criterion Max Ambiguous Bars if (chbAmbiguousBars.Checked && Backtester.AmbiguousBars > nudAmbiguousBars.Value) { return(false); } // Criterion Min Profit per Day if (chbMinProfitPerDay.Checked && Backtester.MoneyProfitPerDay < (double)nudMinProfitPerDay.Value) { return(false); } // Criterion Max Equity Drawdown double maxEquityDrawdown = Configs.AccountInMoney ? Backtester.MaxMoneyEquityDrawdown : Backtester.MaxEquityDrawdown; if (chbMaxDrawdown.Checked && maxEquityDrawdown > (double)nudMaxDrawdown.Value) { return(false); } // Criterion Max Equity percent drawdown if (chbEquityPercent.Checked && Backtester.MoneyEquityPercentDrawdown > (double)nudEquityPercent.Value) { return(false); } // Criterion Min Trades if (chbMinTrades.Checked && Backtester.ExecutedOrders < nudMinTrades.Value) { return(false); } // Criterion Max Trades if (chbMaxTrades.Checked && Backtester.ExecutedOrders > nudMaxTrades.Value) { return(false); } // Criterion Win / Loss ratio if (chbWinLossRatio.Checked && Backtester.WinLossRatio < (double)nudWinLossRatio.Value) { return(false); } // Criterion Minimum Sharpe ratio if (chbMinSharpeRatio.Checked && Backtester.SharpeRatio < (double)nudMinSharpeRatio.Value) { return(false); } // Max consecutive losses if (chbMaxConsecLosses.Checked && Backtester.MaxConsecutiveLosses > nudMaxConsecLosses.Value) { return(false); } // Criterion Red/Green Deviation if (chbMaxRedGreenDeviation.Checked && Backtester.RedGreenBalanceDev > (double)nudMaxRedGreenDeviation.Value) { return(false); } // OOS Pattern filter if (chbOOSPatternFilter.Checked && OOSTesting) { int netBalance = Backtester.NetBalance; int oosBalance = Backtester.Balance(BarOOS); var targetBalance = (int)(oosBalance * TargetBalanceRatio); var minBalance = (int)(targetBalance * (1 - nudoosPatternPercent.Value / 100)); if (netBalance < oosBalance || netBalance < minBalance) { return(false); } } // Smooth Balance Line if (chbSmoothBalanceLines.Checked) { var checkPoints = (int)nudSmoothBalanceCheckPoints.Value; var maxPercentDeviation = (double)(nudSmoothBalancePercent.Value / 100); for (int i = 1; i <= checkPoints; i++) { int firstBar = Data.FirstBar; int bar = Data.FirstBar + i * (Data.Bars - firstBar) / (checkPoints + 1); double netBalance = Backtester.NetMoneyBalance; double startBalance = Backtester.MoneyBalance(firstBar); double checkPointBalance = Backtester.MoneyBalance(bar); double targetBalance = startBalance + i * (netBalance - startBalance) / (checkPoints + 1); double minBalance = targetBalance * (1 - maxPercentDeviation); double maxBalance = targetBalance * (1 + maxPercentDeviation); if (checkPointBalance < minBalance || checkPointBalance > maxBalance) { return(false); } // Long balance line netBalance = Backtester.NetLongMoneyBalance; checkPointBalance = Backtester.LongMoneyBalance(bar); startBalance = Backtester.LongMoneyBalance(firstBar); targetBalance = startBalance + i * (netBalance - startBalance) / (checkPoints + 1); minBalance = targetBalance * (1 - maxPercentDeviation); maxBalance = targetBalance * (1 + maxPercentDeviation); if (checkPointBalance < minBalance || checkPointBalance > maxBalance) { return(false); } // Short balance line netBalance = Backtester.NetShortMoneyBalance; checkPointBalance = Backtester.ShortMoneyBalance(bar); startBalance = Backtester.ShortMoneyBalance(firstBar); targetBalance = startBalance + i * (netBalance - startBalance) / (checkPoints + 1); minBalance = targetBalance * (1 - maxPercentDeviation); maxBalance = targetBalance * (1 + maxPercentDeviation); if (checkPointBalance < minBalance || checkPointBalance > maxBalance) { return(false); } } } return(true); }
/// <summary> /// Check the strategy limitations /// </summary> private bool IsLimitationsFulfilled() { // The calculated strategy has higher profit // or the same profit but lower number of slots Backtester.CalculateAccountStats(); // Limitation Max Ambiguous Bars if (ChbAmbiguousBars.Checked && Backtester.AmbiguousBars > NUDAmbiguousBars.Value) { return(false); } // Limitation Max Equity Drawdown double maxEquityDrawdown = Configs.AccountInMoney ? Backtester.MaxMoneyEquityDrawdown : Backtester.MaxEquityDrawdown; if (ChbMaxDrawdown.Checked && maxEquityDrawdown > (double)NUDMaxDrawdown.Value) { return(false); } // Limitation Max Equity percent drawdown if (ChbEquityPercent.Checked && Backtester.MoneyEquityPercentDrawdown > (double)NUDEquityPercent.Value) { return(false); } // Limitation Min Trades if (ChbMinTrades.Checked && Backtester.ExecutedOrders < NUDMinTrades.Value) { return(false); } // Limitation Max Trades if (ChbMaxTrades.Checked && Backtester.ExecutedOrders > NUDMaxTrades.Value) { return(false); } // Limitation Win / Loss ratio if (ChbWinLossRatio.Checked && Backtester.WinLossRatio < (double)NUDWinLossRatio.Value) { return(false); } // OOS Pattern filter if (ChbOOSPatternFilter.Checked && ChbOutOfSample.Checked) { int netBalance = Backtester.NetBalance; int ooSbalance = Backtester.Balance(_barOOS); var targetBalance = (int)(ooSbalance * _targetBalanceRatio); var minBalance = (int)(targetBalance * (1 - NUDOOSPatternPercent.Value / 100)); if (netBalance < ooSbalance || netBalance < minBalance) { return(false); } } // Smooth Balance Line if (ChbSmoothBalanceLines.Checked) { var checkPoints = (int)NUDSmoothBalanceCheckPoints.Value; var maxPercentDeviation = (double)(NUDSmoothBalancePercent.Value / 100); for (int i = 1; i <= checkPoints; i++) { int firstBar = Data.FirstBar; int bar = Data.FirstBar + i * (Data.Bars - firstBar) / (checkPoints + 1); double netBalance = Backtester.NetMoneyBalance; double startBalance = Backtester.MoneyBalance(firstBar); double checkPointBalance = Backtester.MoneyBalance(bar); double targetBalance = startBalance + i * (netBalance - startBalance) / (checkPoints + 1); double minBalance = targetBalance * (1 - maxPercentDeviation); double maxBalance = targetBalance * (1 + maxPercentDeviation); if (checkPointBalance < minBalance || checkPointBalance > maxBalance) { return(false); } if (Configs.AdditionalStatistics) { // Long balance line netBalance = Backtester.NetLongMoneyBalance; checkPointBalance = Backtester.LongMoneyBalance(bar); startBalance = Backtester.LongMoneyBalance(firstBar); targetBalance = startBalance + i * (netBalance - startBalance) / (checkPoints + 1); minBalance = targetBalance * (1 - maxPercentDeviation); maxBalance = targetBalance * (1 + maxPercentDeviation); if (checkPointBalance < minBalance || checkPointBalance > maxBalance) { return(false); } // Short balance line netBalance = Backtester.NetShortMoneyBalance; checkPointBalance = Backtester.ShortMoneyBalance(bar); startBalance = Backtester.ShortMoneyBalance(firstBar); targetBalance = startBalance + i * (netBalance - startBalance) / (checkPoints + 1); minBalance = targetBalance * (1 - maxPercentDeviation); maxBalance = targetBalance * (1 + maxPercentDeviation); if (checkPointBalance < minBalance || checkPointBalance > maxBalance) { return(false); } } } } return(true); }
/// <summary> /// Calculates the generated result /// </summary> private bool CalculateTheResult(bool isSaveEqualResult) { bool isBetter = false; _cycles++; Data.FirstBar = Data.Strategy.SetFirstBar(); Data.Strategy.AdjustUsePreviousBarValue(); // Sets default logical group for all slots that are open (not locked or linked). foreach (IndicatorSlot slot in Data.Strategy.Slot) { if (slot.SlotStatus == StrategySlotStatus.Open) { slot.LogicalGroup = Data.Strategy.GetDefaultGroup(slot.SlotNumber); } } #if !DEBUG try { #endif Backtester.Calculate(); int balance = (_isOOS ? Backtester.Balance(_barOOS) : Backtester.NetBalance); bool isLimitationsOK = IsLimitationsFulfilled(); if (isLimitationsOK) { if (_bestBalance < balance || (_bestBalance == balance && (isSaveEqualResult || Data.Strategy.Slots < _strategyBest.Slots))) { _strategyBest = Data.Strategy.Clone(); _strategyBest.PropertiesStatus = Data.Strategy.PropertiesStatus; for (int slot = 0; slot < Data.Strategy.Slots; slot++) { _strategyBest.Slot[slot].SlotStatus = Data.Strategy.Slot[slot].SlotStatus; } string description = GenerateDescription(); if (balance > _bestBalance) { AddStrategyToGeneratorHistory(description); } else { UpdateStrategyInGeneratorHistory(description); } SetStrategyDescriptionButton(); _bestBalance = balance; isBetter = true; _isStartegyChanged = true; RefreshSmallBalanceChart(); RefreshAccountStatisticas(); RebuildStrategyLayout(_strategyBest); Top10AddStrategy(); } else if (Top10Field.IsNominated(balance)) { Top10AddStrategy(); } } SetLabelCyclesText(_cycles.ToString(CultureInfo.InvariantCulture)); #if !DEBUG } catch (Exception exception) { string text = GenerateCalculationErrorMessage(exception.Message); const string caption = "Strategy Calculation Error"; ReportIndicatorError(text, caption); isBetter = false; } #endif return(isBetter); }