Ejemplo n.º 1
0
        public CandleChartPanel()
        {
            InitializeComponent();

            var cmdSvc = ConfigManager.GetService <IStudioCommandService>();

            cmdSvc.Register <ChartDrawCommand>(this, false, cmd => _bufferedChart.Draw(cmd.Values));
            cmdSvc.Register <ChartAddAreaCommand>(this, false, cmd => _bufferedChart.AddArea(cmd.Area));
            cmdSvc.Register <ChartRemoveAreaCommand>(this, false, cmd => _bufferedChart.RemoveArea(cmd.Area));
            cmdSvc.Register <ChartAddElementCommand>(this, false, cmd => _bufferedChart.AddElement(cmd.Area, cmd.Element));
            cmdSvc.Register <ChartRemoveElementCommand>(this, false, cmd => _bufferedChart.RemoveElement(cmd.Area, cmd.Element));
            cmdSvc.Register <ChartClearAreasCommand>(this, false, cmd => _bufferedChart.ClearAreas());
            cmdSvc.Register <ChartResetElementsCommand>(this, false, cmd => _bufferedChart.Reset(cmd.Elements));
            cmdSvc.Register <ChartAutoRangeCommand>(this, false, cmd => _bufferedChart.IsAutoRange = cmd.AutoRange);
            cmdSvc.Register <ResetedCommand>(this, true, cmd => OnReseted());
            cmdSvc.Register <BindStrategyCommand>(this, true, cmd =>
            {
                if (!cmd.CheckControl(this))
                {
                    return;
                }

                if (_strategy == cmd.Source)
                {
                    return;
                }

                _strategy = cmd.Source;

                SetChart(true);

                ChartPanel.IsInteracted = _strategy != null && _strategy.GetIsInteracted();

                if (_settingsStorage != null)
                {
                    ChartPanel.Load(_settingsStorage);
                }

                TryCreateDefaultSeries();
            });

            ChartPanel.SettingsChanged           += () => new ControlChangedCommand(this).Process(this);
            ChartPanel.RegisterOrder             += order => new RegisterOrderCommand(order).Process(this);
            ChartPanel.SubscribeCandleElement    += OnChartPanelSubscribeCandleElement;
            ChartPanel.SubscribeIndicatorElement += OnChartPanelSubscribeIndicatorElement;
            ChartPanel.SubscribeOrderElement     += OnChartPanelSubscribeOrderElement;
            ChartPanel.SubscribeTradeElement     += OnChartPanelSubscribeTradeElement;
            ChartPanel.UnSubscribeElement        += OnChartPanelUnSubscribeElement;

            var indicatorTypes = ConfigManager
                                 .GetService <IAlgoService>()
                                 .IndicatorTypes;

            ChartPanel.MinimumRange = 200;
            ChartPanel.IndicatorTypes.AddRange(indicatorTypes);

            _bufferedChart = new BufferedChart(ChartPanel);

            WhenLoaded(() => new RequestBindSource(this).SyncProcess(this));
        }
Ejemplo n.º 2
0
        private void OnLoaded()
        {
            SecurityPicker.SecurityProvider = ConfigManager.GetService <FilterableSecurityProvider>();

            _mainArea = ChartPanel.Areas.FirstOrDefault();

            if (_mainArea == null)
            {
                _bufferedChart.AddArea(_mainArea = new ChartArea {
                    Title = LocalizedStrings.Panel + " 1"
                });
            }

            _candleElement = _mainArea.Elements.OfType <ChartCandleElement>().FirstOrDefault();

            if (_candleElement == null)
            {
                _bufferedChart.AddElement(_mainArea, _candleElement = new ChartCandleElement(), CreateSeries());
            }

            _mainArea
            .Elements
            .OfType <ChartIndicatorElement>()
            .Where(e => _indicators.TryGetValue(e) is CandlePartIndicator)
            .ForEach(e => _sourceElements.Add(((CandleSeries)_bufferedChart.GetSource(e)).Security, e));

            _bufferedChart.AddAction(() =>
            {
                _isLoaded = true;

                if (!HasError)
                {
                    StartSeries();
                }
            });
        }
Ejemplo n.º 3
0
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            InitChart();

            if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text))
            {
                MessageBox.Show(this, LocalizedStrings.Str3014);
                return;
            }

            if (_connectors.Any(t => t.State != EmulationStates.Stopped))
            {
                MessageBox.Show(this, LocalizedStrings.Str3015);
                return;
            }

            var secIdParts = SecId.Text.Split('@');

            if (secIdParts.Length != 2)
            {
                MessageBox.Show(this, LocalizedStrings.Str3016);
                return;
            }

            var timeFrame = TimeSpan.FromMinutes(5);

            // create backtesting modes
            var settings = new[]
            {
                Tuple.Create(
                    TicksCheckBox,
                    TicksTestingProcess,
                    TicksParameterGrid,
                    // ticks
                    new EmulationInfo {
                    UseTicks = true, CurveColor = Colors.DarkGreen, StrategyName = LocalizedStrings.Ticks
                }),

                Tuple.Create(
                    TicksAndDepthsCheckBox,
                    TicksAndDepthsTestingProcess,
                    TicksAndDepthsParameterGrid,
                    // ticks + order book
                    new EmulationInfo {
                    UseTicks = true, UseMarketDepth = true, CurveColor = Colors.Red, StrategyName = LocalizedStrings.XamlStr757
                }),

                Tuple.Create(
                    DepthsCheckBox,
                    DepthsTestingProcess,
                    DepthsParameterGrid,
                    // order book
                    new EmulationInfo {
                    UseMarketDepth = true, CurveColor = Colors.OrangeRed, StrategyName = LocalizedStrings.MarketDepths
                }),


                Tuple.Create(
                    CandlesCheckBox,
                    CandlesTestingProcess,
                    CandlesParameterGrid,
                    // candles
                    new EmulationInfo {
                    UseCandleTimeFrame = timeFrame, CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.Candles
                }),

                Tuple.Create(
                    CandlesAndDepthsCheckBox,
                    CandlesAndDepthsTestingProcess,
                    CandlesAndDepthsParameterGrid,
                    // candles + orderbook
                    new EmulationInfo {
                    UseMarketDepth = true, UseCandleTimeFrame = timeFrame, CurveColor = Colors.Cyan, StrategyName = LocalizedStrings.XamlStr635
                }),

                Tuple.Create(
                    OrderLogCheckBox,
                    OrderLogTestingProcess,
                    OrderLogParameterGrid,
                    // order log
                    new EmulationInfo {
                    UseOrderLog = true, CurveColor = Colors.CornflowerBlue, StrategyName = LocalizedStrings.OrderLog
                })
            };

            // storage to historical data
            var storageRegistry = new StorageRegistry
            {
                // set historical path
                DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text)
            };

            var startTime = ((DateTime)From.Value).ChangeKind(DateTimeKind.Utc);
            var stopTime  = ((DateTime)To.Value).ChangeKind(DateTimeKind.Utc);

            // ОЛ необходимо загружать с 18.45 пред дня, чтобы стаканы строились правильно
            if (OrderLogCheckBox.IsChecked == true)
            {
                startTime = startTime.Subtract(TimeSpan.FromDays(1)).AddHours(18).AddMinutes(45).AddTicks(1);
            }

            // ProgressBar refresh step
            var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>();

            // set ProgressBar bounds
            _progressBars.ForEach(p =>
            {
                p.Value   = 0;
                p.Maximum = 100;
            });

            var logManager      = new LogManager();
            var fileLogListener = new FileLogListener("sample.log");

            logManager.Listeners.Add(fileLogListener);
            //logManager.Listeners.Add(new DebugLogListener());	// for track logs in output window in Vusial Studio (poor performance).

            var generateDepths = GenDepthsCheckBox.IsChecked == true;
            var maxDepth       = MaxDepth.Text.To <int>();
            var maxVolume      = MaxVolume.Text.To <int>();

            var secCode = secIdParts[0];
            var board   = ExchangeBoard.GetOrCreateBoard(secIdParts[1]);

            foreach (var set in settings)
            {
                if (set.Item1.IsChecked == false)
                {
                    continue;
                }

                var progressBar   = set.Item2;
                var statistic     = set.Item3;
                var emulationInfo = set.Item4;

                // create test security
                var security = new Security
                {
                    Id    = SecId.Text,                  // sec id has the same name as folder with historical data
                    Code  = secCode,
                    Board = board,
                };

                var level1Info = new Level1ChangeMessage
                {
                    SecurityId = security.ToSecurityId(),
                    ServerTime = startTime,
                }
                .TryAdd(Level1Fields.PriceStep, 10m)
                .TryAdd(Level1Fields.StepPrice, 6m)
                .TryAdd(Level1Fields.MinPrice, 10m)
                .TryAdd(Level1Fields.MaxPrice, 1000000m)
                .TryAdd(Level1Fields.MarginBuy, 10000m)
                .TryAdd(Level1Fields.MarginSell, 10000m);

                // test portfolio
                var portfolio = new Portfolio
                {
                    Name       = "test account",
                    BeginValue = 1000000,
                };

                // create backtesting connector
                var connector = new HistoryEmulationConnector(
                    new[] { security },
                    new[] { portfolio })
                {
                    MarketEmulator =
                    {
                        Settings         =
                        {
                            // match order if historical price touched our limit order price.
                            // It is terned off, and price should go through limit order price level
                            // (more "severe" test mode)
                            MatchOnTouch = false,
                        }
                    },

                    UseExternalCandleSource = emulationInfo.UseCandleTimeFrame != null,

                    CreateDepthFromOrdersLog  = emulationInfo.UseOrderLog,
                    CreateTradesFromOrdersLog = emulationInfo.UseOrderLog,

                    HistoryMessageAdapter =
                    {
                        StorageRegistry = storageRegistry,

                        // set history range
                        StartDate = startTime,
                        StopDate  = stopTime,
                    },

                    // set market time freq as time frame
                    MarketTimeChangedInterval = timeFrame,
                };

                ((ILogSource)connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info;

                logManager.Sources.Add(connector);

                var candleManager = emulationInfo.UseCandleTimeFrame == null
                                        ? new CandleManager(new TradeCandleBuilderSourceEx(connector))
                                        : new CandleManager(connector);

                var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);

                _shortMa = new SimpleMovingAverage {
                    Length = 10
                };
                _shortElem = new ChartIndicatorElement
                {
                    Color          = Colors.Coral,
                    ShowAxisMarker = false,
                    FullTitle      = _shortMa.ToString()
                };
                _bufferedChart.AddElement(_area, _shortElem);

                _longMa = new SimpleMovingAverage {
                    Length = 80
                };
                _longElem = new ChartIndicatorElement
                {
                    ShowAxisMarker = false,
                    FullTitle      = _longMa.ToString()
                };
                _bufferedChart.AddElement(_area, _longElem);

                // create strategy based on 80 5-min и 10 5-min
                var strategy = new SmaStrategy(_bufferedChart, _candlesElem, _tradesElem, _shortMa, _shortElem, _longMa, _longElem, series)
                {
                    Volume    = 1,
                    Portfolio = portfolio,
                    Security  = security,
                    Connector = connector,
                    LogLevel  = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info,

                    // by default interval is 1 min,
                    // it is excessively for time range with several months
                    UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>()
                };

                logManager.Sources.Add(strategy);

                connector.NewSecurities += securities =>
                {
                    if (securities.All(s => s != security))
                    {
                        return;
                    }

                    // fill level1 values
                    connector.SendInMessage(level1Info);

                    if (emulationInfo.UseMarketDepth)
                    {
                        connector.RegisterMarketDepth(security);

                        if (
                            // if order book will be generated
                            generateDepths ||
                            // of backtesting will be on candles
                            emulationInfo.UseCandleTimeFrame != TimeSpan.Zero
                            )
                        {
                            // if no have order book historical data, but strategy is required,
                            // use generator based on last prices
                            connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security))
                            {
                                Interval           = TimeSpan.FromSeconds(1),                       // order book freq refresh is 1 sec
                                MaxAsksDepth       = maxDepth,
                                MaxBidsDepth       = maxDepth,
                                UseTradeVolume     = true,
                                MaxVolume          = maxVolume,
                                MinSpreadStepCount = 2,                                 // min spread generation is 2 pips
                                MaxSpreadStepCount = 5,                                 // max spread generation size (prevent extremely size)
                                MaxPriceStepCount  = 3                                  // pips size,
                            });
                        }
                    }

                    if (emulationInfo.UseOrderLog)
                    {
                        connector.RegisterOrderLog(security);
                    }

                    if (emulationInfo.UseTicks)
                    {
                        connector.RegisterTrades(security);
                    }

                    // start strategy before emulation started
                    strategy.Start();
                    candleManager.Start(series);

                    // start historical data loading when connection established successfully and all data subscribed
                    connector.Start();
                };

                // fill parameters panel
                statistic.Parameters.Clear();
                statistic.Parameters.AddRange(strategy.StatisticManager.Parameters);

                var pnlCurve           = Curve.CreateCurve("P&L " + emulationInfo.StrategyName, emulationInfo.CurveColor, EquityCurveChartStyles.Area);
                var unrealizedPnLCurve = Curve.CreateCurve(LocalizedStrings.PnLUnreal + emulationInfo.StrategyName, Colors.Black);
                var commissionCurve    = Curve.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, EquityCurveChartStyles.DashedLine);
                var posItems           = PositionCurve.CreateCurve(emulationInfo.StrategyName, emulationInfo.CurveColor);
                strategy.PnLChanged += () =>
                {
                    var pnl = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.PnL - strategy.Commission ?? 0
                    };

                    var unrealizedPnL = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.PnLManager.UnrealizedPnL
                    };

                    var commission = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.Commission ?? 0
                    };

                    pnlCurve.Add(pnl);
                    unrealizedPnLCurve.Add(unrealizedPnL);
                    commissionCurve.Add(commission);
                };

                strategy.PositionChanged += () => posItems.Add(new EquityData {
                    Time = strategy.CurrentTime, Value = strategy.Position
                });

                var nextTime = startTime + progressStep;

                // handle historical time for update ProgressBar
                connector.MarketTimeChanged += d =>
                {
                    if (connector.CurrentTime < nextTime && connector.CurrentTime < stopTime)
                    {
                        return;
                    }

                    var steps = (connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1;
                    nextTime = startTime + (steps * progressStep.Ticks).To <TimeSpan>();
                    this.GuiAsync(() => progressBar.Value = steps);
                };

                connector.StateChanged += () =>
                {
                    if (connector.State == EmulationStates.Stopped)
                    {
                        candleManager.Stop(series);
                        strategy.Stop();

                        logManager.Dispose();
                        _connectors.Clear();

                        SetIsEnabled(false);

                        this.GuiAsync(() =>
                        {
                            if (connector.IsFinished)
                            {
                                progressBar.Value = progressBar.Maximum;
                                MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime));
                            }
                            else
                            {
                                MessageBox.Show(this, LocalizedStrings.cancelled);
                            }
                        });
                    }
                    else if (connector.State == EmulationStates.Started)
                    {
                        SetIsEnabled(true);
                    }
                };

                if (ShowDepth.IsChecked == true)
                {
                    MarketDepth.UpdateFormat(security);

                    connector.NewMessage += message =>
                    {
                        var quoteMsg = message as QuoteChangeMessage;

                        if (quoteMsg != null)
                        {
                            MarketDepth.UpdateDepth(quoteMsg);
                        }
                    };
                }

                _connectors.Add(connector);

                progressBar.Value = 0;
            }

            _startEmulationTime = DateTime.Now;

            // start emulation
            foreach (var connector in _connectors)
            {
                // raise NewSecurities and NewPortfolio for full fill strategy properties
                connector.Connect();

                // 1 cent commission for trade
                connector.SendInMessage(new CommissionRuleMessage
                {
                    Rule = new CommissionPerTradeRule {
                        Value = 0.01m
                    }
                });
            }

            TabControl.Items.Cast <TabItem>().First(i => i.Visibility == Visibility.Visible).IsSelected = true;
        }
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            InitChart();

            if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text))
            {
                MessageBox.Show(this, LocalizedStrings.Str3014);
                return;
            }

            var secGen     = new SecurityIdGenerator();
            var secIdParts = secGen.Split(SecId.Text);

            var storageRegistry = new StorageRegistry()
            {
                DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text)
            };

            var startTime = ((DateTime)From.Value).ChangeKind(DateTimeKind.Utc);
            var stopTime  = ((DateTime)To.Value).ChangeKind(DateTimeKind.Utc);

            //var logManager = new LogManager();
            //var fileLogListener = new FileLogListener("sample.log");
            //logManager.Listeners.Add(fileLogListener);
            //logManager.Listeners.Add(new DebugLogListener());	// for track logs in output window in Vusial Studio (poor performance).

            var maxDepth  = 5;
            var maxVolume = 5;

            var secCode = secIdParts.Item1;
            var board   = ExchangeBoard.GetOrCreateBoard(secIdParts.Item2);

            var progressBar  = TicksTestingProcess;
            var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>();

            progressBar.Value   = 0;
            progressBar.Maximum = 100;

            var statistic = TicksParameterGrid;
            var security  = new Security()
            {
                Id    = SecId.Text,
                Code  = secCode,
                Board = board,
            };

            var portfolio = new Portfolio()
            {
                Name       = "test account",
                BeginValue = 1000000,
            };

            var connector = new HistoryEmulationConnector(new[] { security }, new[] { portfolio })
            {
                EmulationAdapter =
                {
                    Emulator     =
                    {
                        Settings = { MatchOnTouch = true, PortfolioRecalcInterval = TimeSpan.FromMilliseconds(100), SpreadSize = 1, },
                        LogLevel = LogLevels.Debug,
                    },
                    LogLevel     = LogLevels.Debug,
                },
                HistoryMessageAdapter = { StorageRegistry = storageRegistry, StartDate = startTime, StopDate = stopTime, MarketTimeChangedInterval = TimeSpan.FromMilliseconds(50), },
            };

            //logManager.Sources.Add(connector);

            var candleManager = new CandleManager(connector);
            var series        = new CandleSeries(typeof(RangeCandle), security, new Unit(100));

            shortMa = new SimpleMovingAverage {
                Length = 10
            };
            shortElem = new ChartIndicatorElement
            {
                Color          = Colors.Coral,
                ShowAxisMarker = false,
                FullTitle      = shortMa.ToString()
            };
            bufferedChart.AddElement(area, shortElem);

            longMa = new SimpleMovingAverage {
                Length = 30
            };
            longElem = new ChartIndicatorElement
            {
                ShowAxisMarker = false,
                FullTitle      = longMa.ToString()
            };

            bufferedChart.AddElement(area, longElem);

            var strategy = new SmaStrategy(bufferedChart, candlesElem, tradesElem, shortMa, shortElem, longMa, longElem, series)
            {
                Volume                = 1,
                Portfolio             = portfolio,
                Security              = security,
                Connector             = connector,
                LogLevel              = LogLevels.Debug,
                UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>()
            };

            //logManager.Sources.Add(strategy);

            connector.NewSecurities += securities =>
            {
                if (securities.All(s => s != security))
                {
                    return;
                }

                connector.RegisterMarketDepth(security);
                connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security))
                {
                    Interval           = TimeSpan.FromMilliseconds(100),       // order book freq refresh is 1 sec
                    MaxAsksDepth       = maxDepth,
                    MaxBidsDepth       = maxDepth,
                    UseTradeVolume     = true,
                    MaxVolume          = maxVolume,
                    MinSpreadStepCount = 1,     // min spread generation is 2 pips
                    MaxSpreadStepCount = 1,     // max spread generation size (prevent extremely size)
                    MaxPriceStepCount  = 3      // pips size,
                });

                connector.RegisterTrades(security);
                connector.RegisterSecurity(security);

                strategy.Start();
                candleManager.Start(series);

                connector.Start();
            };

            statistic.Parameters.Clear();
            statistic.Parameters.AddRange(strategy.StatisticManager.Parameters);

            var pnlCurve           = Curve.CreateCurve(LocalizedStrings.PnL + " " + StrategyName, Colors.Cyan, EquityCurveChartStyles.Area);
            var unrealizedPnLCurve = Curve.CreateCurve(LocalizedStrings.PnLUnreal + StrategyName, Colors.Black);
            var commissionCurve    = Curve.CreateCurve(LocalizedStrings.Str159 + " " + StrategyName, Colors.Red, EquityCurveChartStyles.DashedLine);
            var posItems           = PositionCurve.CreateCurve(StrategyName, Colors.Crimson);

            strategy.PnLChanged += () =>
            {
                var pnl = new EquityData()
                {
                    Time = strategy.CurrentTime, Value = strategy.PnL - strategy.Commission ?? 0
                };
                var unrealizedPnL = new EquityData()
                {
                    Time = strategy.CurrentTime, Value = strategy.PnLManager.UnrealizedPnL
                };
                var commission = new EquityData()
                {
                    Time = strategy.CurrentTime, Value = strategy.Commission ?? 0
                };

                pnlCurve.Add(pnl);
                unrealizedPnLCurve.Add(unrealizedPnL);
                commissionCurve.Add(commission);
            };

            strategy.PositionChanged += () => posItems.Add(new EquityData {
                Time = strategy.CurrentTime, Value = strategy.Position
            });

            var nextTime = startTime + progressStep;

            connector.MarketTimeChanged += d =>
            {
                if (connector.CurrentTime < nextTime && connector.CurrentTime < stopTime)
                {
                    return;
                }

                var steps = (connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1;
                nextTime = startTime + (steps * progressStep.Ticks).To <TimeSpan>();
                this.GuiAsync(() => progressBar.Value = steps);
            };

            connector.StateChanged += () =>
            {
                if (connector.State == EmulationStates.Stopped)
                {
                    candleManager.Stop(series);
                    strategy.Stop();

                    //logManager.Dispose();

                    SetIsEnabled(false);

                    this.GuiAsync(() =>
                    {
                        if (connector.IsFinished)
                        {
                            progressBar.Value = progressBar.Maximum;
                            MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - startEmulationTime));
                        }
                        else
                        {
                            MessageBox.Show(this, LocalizedStrings.cancelled);
                        }
                    });
                }
                else if (connector.State == EmulationStates.Started)
                {
                    SetIsEnabled(true);
                }
            };

            progressBar.Value  = 0;
            startEmulationTime = DateTime.Now;

            connector.Connect();
            connector.SendInMessage(new CommissionRuleMessage()
            {
                Rule = new CommissionPerTradeRule {
                    Value = 0.01m
                }
            });
        }
Ejemplo n.º 5
0
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            InitChart();

            if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text))
            {
                MessageBox.Show(this, LocalizedStrings.Str3014);
                return;
            }

            if (_connectors.Any(t => t.State != EmulationStates.Stopped))
            {
                MessageBox.Show(this, LocalizedStrings.Str3015);
                return;
            }

            var secIdParts = SecId.Text.Split('@');

            if (secIdParts.Length != 2)
            {
                MessageBox.Show(this, LocalizedStrings.Str3016);
                return;
            }

            var timeFrame = TimeSpan.FromMinutes(5);

            // создаем настройки для тестирования
            var settings = new[]
            {
                Tuple.Create(
                    TicksCheckBox,
                    TicksTestingProcess,
                    TicksParameterGrid,
                    // тест только на тиках
                    new EmulationInfo {
                    CurveColor = Colors.DarkGreen, StrategyName = LocalizedStrings.Str3017
                }),

                Tuple.Create(
                    TicksAndDepthsCheckBox,
                    TicksAndDepthsTestingProcess,
                    TicksAndDepthsParameterGrid,
                    // тест на тиках + стаканы
                    new EmulationInfo {
                    UseMarketDepth = true, CurveColor = Colors.Red, StrategyName = LocalizedStrings.Str3018
                }),

                Tuple.Create(
                    CandlesCheckBox,
                    CandlesTestingProcess,
                    CandlesParameterGrid,
                    // тест на свечах
                    new EmulationInfo {
                    UseCandleTimeFrame = timeFrame, CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.Str3019
                }),

                Tuple.Create(
                    CandlesAndDepthsCheckBox,
                    CandlesAndDepthsTestingProcess,
                    CandlesAndDepthsParameterGrid,
                    // тест на свечах + стаканы
                    new EmulationInfo {
                    UseMarketDepth = true, UseCandleTimeFrame = timeFrame, CurveColor = Colors.Cyan, StrategyName = LocalizedStrings.Str3020
                }),

                Tuple.Create(
                    OrderLogCheckBox,
                    OrderLogTestingProcess,
                    OrderLogParameterGrid,
                    // тест на логе заявок
                    new EmulationInfo {
                    UseOrderLog = true, CurveColor = Colors.CornflowerBlue, StrategyName = LocalizedStrings.Str3021
                })
            };

            // хранилище, через которое будет производиться доступ к тиковой и котировочной базе
            var storageRegistry = new StorageRegistry
            {
                // изменяем путь, используемый по умолчанию
                DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text)
            };

            var startTime = (DateTime)From.Value;
            var stopTime  = (DateTime)To.Value;

            // ОЛ необходимо загружать с 18.45 пред дня, чтобы стаканы строились правильно
            if (OrderLogCheckBox.IsChecked == true)
            {
                startTime = startTime.Subtract(TimeSpan.FromDays(1)).AddHours(18).AddMinutes(45).AddTicks(1);
            }

            // задаем шаг ProgressBar
            var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>();

            // в реальности период может быть другим, и это зависит от объема данных,
            // хранящихся по пути HistoryPath,
            TicksTestingProcess.Maximum = TicksAndDepthsTestingProcess.Maximum = CandlesTestingProcess.Maximum = 100;
            TicksTestingProcess.Value   = TicksAndDepthsTestingProcess.Value = CandlesTestingProcess.Value = 0;

            var logManager      = new LogManager();
            var fileLogListener = new FileLogListener("sample.log");

            logManager.Listeners.Add(fileLogListener);
            //logManager.Listeners.Add(new DebugLogListener());	// чтобы смотреть логи в отладчике - работает медленно.

            var generateDepths = GenDepthsCheckBox.IsChecked == true;
            var maxDepth       = MaxDepth.Text.To <int>();
            var maxVolume      = MaxVolume.Text.To <int>();

            var secCode = secIdParts[0];
            var board   = ExchangeBoard.GetOrCreateBoard(secIdParts[1]);

            foreach (var set in settings)
            {
                if (set.Item1.IsChecked == false)
                {
                    continue;
                }

                var progressBar   = set.Item2;
                var statistic     = set.Item3;
                var emulationInfo = set.Item4;

                // создаем тестовый инструмент, на котором будет производится тестирование
                var security = new Security
                {
                    Id    = SecId.Text,                  // по идентификатору инструмента будет искаться папка с историческими маркет данными
                    Code  = secCode,
                    Board = board,
                };

                var level1Info = new Level1ChangeMessage
                {
                    SecurityId = security.ToSecurityId(),
                    ServerTime = startTime,
                }
                .TryAdd(Level1Fields.PriceStep, 10m)
                .TryAdd(Level1Fields.StepPrice, 6m)
                .TryAdd(Level1Fields.MinPrice, 10m)
                .TryAdd(Level1Fields.MaxPrice, 1000000m)
                .TryAdd(Level1Fields.MarginBuy, 10000m)
                .TryAdd(Level1Fields.MarginSell, 10000m);

                // тестовый портфель
                var portfolio = new Portfolio
                {
                    Name       = "test account",
                    BeginValue = 1000000,
                };

                // создаем подключение для эмуляции
                // инициализируем настройки (инструмент в истории обновляется раз в секунду)
                var connector = new HistoryEmulationConnector(
                    new[] { security },
                    new[] { portfolio })
                {
                    StorageRegistry = storageRegistry,

                    MarketEmulator =
                    {
                        Settings                =
                        {
                            // использовать свечи
                            UseCandlesTimeFrame = emulationInfo.UseCandleTimeFrame,

                            // сведение сделки в эмуляторе если цена коснулась нашей лимитной заявки.
                            // Если выключено - требуется "прохождение цены сквозь уровень"
                            // (более "суровый" режим тестирования.)
                            MatchOnTouch        = false,
                        }
                    },

                    //UseExternalCandleSource = true,
                    CreateDepthFromOrdersLog  = emulationInfo.UseOrderLog,
                    CreateTradesFromOrdersLog = emulationInfo.UseOrderLog,
                };

                connector.MarketDataAdapter.SessionHolder.MarketTimeChangedInterval = timeFrame;

                ((ILogSource)connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info;

                logManager.Sources.Add(connector);

                connector.NewSecurities += securities =>
                {
                    //подписываемся на получение данных после получения инструмента

                    if (securities.All(s => s != security))
                    {
                        return;
                    }

                    // отправляем данные Level1 для инструмента
                    connector.MarketDataAdapter.SendOutMessage(level1Info);

                    // тест подразумевает наличие стаканов
                    if (emulationInfo.UseMarketDepth)
                    {
                        connector.RegisterMarketDepth(security);

                        if (
                            // если выбрана генерация стаканов вместо реальных стаканов
                            generateDepths ||
                            // для свечей генерируем стаканы всегда
                            emulationInfo.UseCandleTimeFrame != TimeSpan.Zero
                            )
                        {
                            // если история по стаканам отсутствует, но стаканы необходимы для стратегии,
                            // то их можно сгенерировать на основании цен последних сделок или свечек.
                            connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security))
                            {
                                Interval           = TimeSpan.FromSeconds(1),                       // стакан для инструмента в истории обновляется раз в секунду
                                MaxAsksDepth       = maxDepth,
                                MaxBidsDepth       = maxDepth,
                                UseTradeVolume     = true,
                                MaxVolume          = maxVolume,
                                MinSpreadStepCount = 2,                                 // минимальный генерируемый спред - 2 минимальных шага цены
                                MaxSpreadStepCount = 5,                                 // не генерировать спрэд между лучшим бид и аск больше чем 5 минимальных шагов цены - нужно чтобы при генерации из свечей не получалось слишком широкого спреда.
                                MaxPriceStepCount  = 3                                  // максимальное количество шагов между ценами,
                            });
                        }
                    }
                    else if (emulationInfo.UseOrderLog)
                    {
                        connector.RegisterOrderLog(security);
                    }
                };

                // соединяемся с трейдером и запускаем экспорт,
                // чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader
                connector.Connect();
                connector.StartExport();

                var candleManager = new CandleManager(connector);
                var series        = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);

                _shortMa = new SimpleMovingAverage {
                    Length = 10
                };
                _shortElem = new ChartIndicatorElement
                {
                    Color          = Colors.Coral,
                    ShowAxisMarker = false,
                    FullTitle      = _shortMa.ToString()
                };
                _bufferedChart.AddElement(_area, _shortElem);

                _longMa = new SimpleMovingAverage {
                    Length = 80
                };
                _longElem = new ChartIndicatorElement
                {
                    ShowAxisMarker = false,
                    FullTitle      = _longMa.ToString()
                };
                _bufferedChart.AddElement(_area, _longElem);

                // создаем торговую стратегию, скользящие средние на 80 5-минуток и 10 5-минуток
                var strategy = new SmaStrategy(_bufferedChart, _candlesElem, _tradesElem, _shortMa, _shortElem, _longMa, _longElem, series)
                {
                    Volume    = 1,
                    Portfolio = portfolio,
                    Security  = security,
                    Connector = connector,
                    LogLevel  = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info,

                    // по-умолчанию интервал равен 1 минут,
                    // что для истории в диапазон от нескольких месяцев излишне
                    UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>()
                };

                // комиссия в 1 копейку за сделку
                connector.MarketEmulator.SendInMessage(new CommissionRuleMessage
                {
                    Rule = new CommissionPerTradeRule {
                        Value = 0.01m
                    }
                });

                logManager.Sources.Add(strategy);

                // копируем параметры на визуальную панель
                statistic.Parameters.Clear();
                statistic.Parameters.AddRange(strategy.StatisticManager.Parameters);

                var pnlCurve           = Curve.CreateCurve("P&L " + emulationInfo.StrategyName, emulationInfo.CurveColor, EquityCurveChartStyles.Area);
                var unrealizedPnLCurve = Curve.CreateCurve(LocalizedStrings.PnLUnreal + emulationInfo.StrategyName, Colors.Black);
                var commissionCurve    = Curve.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, EquityCurveChartStyles.DashedLine);
                var posItems           = PositionCurve.CreateCurve(emulationInfo.StrategyName, emulationInfo.CurveColor);
                strategy.PnLChanged += () =>
                {
                    var pnl = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.PnL - strategy.Commission ?? 0
                    };

                    var unrealizedPnL = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.PnLManager.UnrealizedPnL
                    };

                    var commission = new EquityData
                    {
                        Time  = strategy.CurrentTime,
                        Value = strategy.Commission ?? 0
                    };

                    pnlCurve.Add(pnl);
                    unrealizedPnLCurve.Add(unrealizedPnL);
                    commissionCurve.Add(commission);
                };

                strategy.PositionChanged += () => posItems.Add(new EquityData {
                    Time = strategy.CurrentTime, Value = strategy.Position
                });

                var nextTime = startTime + progressStep;

                // и подписываемся на событие изменения времени, чтобы обновить ProgressBar
                connector.MarketTimeChanged += d =>
                {
                    if (connector.CurrentTime < nextTime && connector.CurrentTime < stopTime)
                    {
                        return;
                    }

                    var steps = (connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1;
                    nextTime = startTime + (steps * progressStep.Ticks).To <TimeSpan>();
                    this.GuiAsync(() => progressBar.Value = steps);
                };

                connector.StateChanged += () =>
                {
                    if (connector.State == EmulationStates.Stopped)
                    {
                        candleManager.Stop(series);
                        strategy.Stop();

                        logManager.Dispose();
                        _connectors.Clear();

                        SetIsEnabled(false);

                        this.GuiAsync(() =>
                        {
                            if (connector.IsFinished)
                            {
                                progressBar.Value = progressBar.Maximum;
                                MessageBox.Show(LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime));
                            }
                            else
                            {
                                MessageBox.Show(LocalizedStrings.cancelled);
                            }
                        });
                    }
                    else if (connector.State == EmulationStates.Started)
                    {
                        SetIsEnabled(true);

                        // запускаем стратегию когда эмулятор запустился
                        strategy.Start();
                        candleManager.Start(series);
                    }
                };

                if (ShowDepth.IsChecked == true)
                {
                    MarketDepth.UpdateFormat(security);

                    connector.NewMessage += (message, dir) =>
                    {
                        var quoteMsg = message as QuoteChangeMessage;

                        if (quoteMsg != null)
                        {
                            MarketDepth.UpdateDepth(quoteMsg);
                        }
                    };
                }

                _connectors.Add(connector);
            }

            _startEmulationTime = DateTime.Now;

            // запускаем эмуляцию
            foreach (var connector in _connectors)
            {
                // указываем даты начала и конца тестирования
                connector.Start(startTime, stopTime);
            }

            TabControl.Items.Cast <TabItem>().First(i => i.Visibility == Visibility.Visible).IsSelected = true;
        }