/// <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> /// 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> /// 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; } }
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); }