Esempio n. 1
0
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            // if process was already started, will stop it now
            if (_connector != null && _connector.State != EmulationStates.Stopped)
            {
                _strategy.Stop();
                _connector.Disconnect();
                _logManager.Sources.Clear();

                _connector = null;
                return;
            }

            // create test security
            var security = new Security
            {
                Id    = "AAPL@NASDAQ",
                Code  = "AAPL",
                Name  = "AAPL Inc",
                Board = ExchangeBoard.Nasdaq,
            };

            var startTime = new DateTime(2009, 6, 1);
            var stopTime  = new DateTime(2009, 9, 1);

            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,
            };

            var timeFrame = TimeSpan.FromMinutes(5);

            // create backtesting connector
            _connector = new HistoryEmulationConnector(
                new[] { security },
                new[] { portfolio })
            {
                HistoryMessageAdapter =
                {
                    // set history range
                    StartDate = startTime,
                    StopDate  = stopTime,
                },

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

            _logManager.Sources.Add(_connector);

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

            // create strategy based on 80 5-min и 10 5-min
            _strategy = new SmaStrategy(_connector, series, new SimpleMovingAverage {
                Length = 80
            }, new SimpleMovingAverage {
                Length = 10
            })
            {
                Volume    = 1,
                Security  = security,
                Portfolio = portfolio,
                Connector = _connector,
            };

            _connector.NewSecurity += s =>
            {
                if (s != security)
                {
                    return;
                }

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

                _connector.RegisterTrades(new RandomWalkTradeGenerator(_connector.GetSecurityId(security)));
                _connector.RegisterMarketDepth(new TrendMarketDepthGenerator(_connector.GetSecurityId(security))
                {
                    GenerateDepthOnEachTrade = false
                });

                // start strategy before emulation started
                _strategy.Start();
                _connector.SubscribeCandles(series);

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

            // fill parameters panel
            ParameterGrid.Parameters.Clear();
            ParameterGrid.Parameters.AddRange(_strategy.StatisticManager.Parameters);

            _strategy.PnLChanged += () =>
            {
                var data = new ChartDrawData();

                data
                .Group(_strategy.CurrentTime)
                .Add(_curveElem, _strategy.PnL);

                Curve.Draw(data);
            };

            _logManager.Sources.Add(_strategy);

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

            TestingProcess.Maximum = 100;
            TestingProcess.Value   = 0;

            // handle historical time for update ProgressBar
            _connector.MarketTimeChanged += diff =>
            {
                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(() => TestingProcess.Value = steps);
            };

            _connector.StateChanged += () =>
            {
                if (_connector.State == EmulationStates.Stopped)
                {
                    this.GuiAsync(() =>
                    {
                        Report.IsEnabled = true;

                        if (_connector.IsFinished)
                        {
                            TestingProcess.Value = TestingProcess.Maximum;
                            MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime));
                        }
                        else
                        {
                            MessageBox.Show(this, LocalizedStrings.cancelled);
                        }
                    });
                }
            };

            Curve.Reset(new[] { _curveElem });

            Report.IsEnabled = false;

            _startEmulationTime = DateTime.Now;

            // raise NewSecurities and NewPortfolio for full fill strategy properties
            _connector.Connect();
        }
Esempio n. 2
0
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            if (_connectors.Count > 0)
            {
                foreach (var connector in _connectors)
                {
                    connector.Start();
                }

                return;
            }

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

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

            var id = SecId.Text.ToSecurityId();

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

            var timeFrame = TimeSpan.FromMinutes(TimeFrame.SelectedIndex == 0 ? 1 : 5);

            var secCode = id.SecurityCode;
            var board   = _exchangeInfoProvider.GetOrCreateBoard(id.BoardCode);

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

            if (FinamCandlesCheckBox.IsChecked == true)
            {
                _finamHistorySource.Refresh(new FinamSecurityStorage(security), security, s => {}, () => false);
            }

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

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

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

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

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

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

                Tuple.Create(
                    Level1CheckBox,
                    Level1Progress,
                    Level1ParameterGrid,
                    // order log
                    new EmulationInfo {
                    UseLevel1 = true, CurveColor = Colors.Aquamarine, StrategyName = LocalizedStrings.Level1
                },
                    Level1Chart,
                    Level1Equity,
                    Level1Position),

                Tuple.Create(
                    FinamCandlesCheckBox,
                    FinamCandlesProgress,
                    FinamCandlesParameterGrid,
                    // candles
                    new EmulationInfo {
                    UseCandleTimeFrame = timeFrame, HistorySource = d => _finamHistorySource.GetCandles(security, timeFrame, d.Date, d.Date), CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.FinamCandles
                },
                    FinamCandlesChart,
                    FinamCandlesEquity,
                    FinamCandlesPosition),

                Tuple.Create(
                    YahooCandlesCheckBox,
                    YahooCandlesProgress,
                    YahooCandlesParameterGrid,
                    // candles
                    new EmulationInfo {
                    UseCandleTimeFrame = timeFrame, HistorySource = d => new YahooHistorySource(_nativeIdStorage, _exchangeInfoProvider).GetCandles(security, timeFrame, d.Date, d.Date), CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.YahooCandles
                },
                    YahooCandlesChart,
                    YahooCandlesEquity,
                    YahooCandlesPosition),
            };

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

            var startTime = ((DateTime)From.EditValue).UtcKind();
            var stopTime  = ((DateTime)To.EditValue).UtcKind();

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

            // 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 secId          = security.ToSecurityId();

            SetIsEnabled(false, false, false);

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

                var title = (string)set.Item1.Content;

                InitChart(set.Item5, set.Item6, set.Item7);

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

                var level1Info = new Level1ChangeMessage
                {
                    SecurityId = secId,
                    ServerTime = startTime,
                }
                .TryAdd(Level1Fields.PriceStep, secCode == "RIZ2" ? 10m : 1)
                .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 })
                {
                    EmulationAdapter =
                    {
                        Emulator             =
                        {
                            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,

                        OrderLogMarketDepthBuilders =
                        {
                            {
                                secId,
                                new OrderLogMarketDepthBuilder(secId)
                            }
                        }
                    },

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

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

                logManager.Sources.Add(connector);

                var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame)
                {
                    BuildCandlesMode = emulationInfo.UseCandleTimeFrame == null ? MarketDataBuildModes.Build : MarketDataBuildModes.Load,
                    BuildCandlesFrom = emulationInfo.UseOrderLog ? (MarketDataTypes?)MarketDataTypes.OrderLog : null,
                };

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

                var chart = set.Item5;

                chart.AddElement(_area, _shortElem);

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

                // create strategy based on 80 5-min и 10 5-min
                var strategy = new SmaStrategy(chart, _candlesElem, _tradesElem, _shortMa, _shortElem, _longMa, _longElem, connector, 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.Connected += () =>
                {
                    if (emulationInfo.HistorySource != null)
                    {
                        // passing null value as security to register the source for all securities

                        if (emulationInfo.UseCandleTimeFrame != null)
                        {
                            connector.RegisterHistorySource(null, MarketDataTypes.CandleTimeFrame, emulationInfo.UseCandleTimeFrame.Value, emulationInfo.HistorySource);
                        }

                        if (emulationInfo.UseTicks)
                        {
                            connector.RegisterHistorySource(null, MarketDataTypes.Trades, null, emulationInfo.HistorySource);
                        }

                        if (emulationInfo.UseLevel1)
                        {
                            connector.RegisterHistorySource(null, MarketDataTypes.Level1, null, emulationInfo.HistorySource);
                        }

                        if (emulationInfo.UseMarketDepth)
                        {
                            connector.RegisterHistorySource(null, MarketDataTypes.MarketDepth, null, emulationInfo.HistorySource);
                        }
                    }
                };

                connector.NewSecurity += s =>
                {
                    if (s != security)
                    {
                        return;
                    }

                    // fill level1 values
                    connector.HistoryMessageAdapter.SendOutMessage(level1Info);

                    if (emulationInfo.HistorySource == null)
                    {
                        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);
                        }

                        if (emulationInfo.UseLevel1)
                        {
                            connector.RegisterSecurity(security);
                        }
                    }

                    // start strategy before emulation started
                    strategy.Start();
                    connector.SubscribeCandles(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 equity = set.Item6;

                var pnlCurve           = equity.CreateCurve(LocalizedStrings.PnL + " " + emulationInfo.StrategyName, Colors.Green, Colors.Red, ChartIndicatorDrawStyles.Area);
                var unrealizedPnLCurve = equity.CreateCurve(LocalizedStrings.PnLUnreal + " " + emulationInfo.StrategyName, Colors.Black, ChartIndicatorDrawStyles.Line);
                var commissionCurve    = equity.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, ChartIndicatorDrawStyles.DashedLine);

                strategy.PnLChanged += () =>
                {
                    var data = new ChartDrawData();

                    data
                    .Group(strategy.CurrentTime)
                    .Add(pnlCurve, strategy.PnL - strategy.Commission ?? 0)
                    .Add(unrealizedPnLCurve, strategy.PnLManager.UnrealizedPnL ?? 0)
                    .Add(commissionCurve, strategy.Commission ?? 0);

                    equity.Draw(data);
                };

                var posItems = set.Item7.CreateCurve(emulationInfo.StrategyName, emulationInfo.CurveColor, ChartIndicatorDrawStyles.Line);

                strategy.PositionChanged += () =>
                {
                    var data = new ChartDrawData();

                    data
                    .Group(strategy.CurrentTime)
                    .Add(posItems, strategy.Position);

                    set.Item7.Draw(data);
                };

                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)
                    {
                        connector.UnSubscribeCandles(series);
                        strategy.Stop();

                        SetIsChartEnabled(chart, false);

                        if (_connectors.All(c => c.State == EmulationStates.Stopped))
                        {
                            logManager.Dispose();
                            _connectors.Clear();

                            SetIsEnabled(true, false, false);
                        }

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

                        SetIsChartEnabled(chart, true);
                    }
                    else if (connector.State == EmulationStates.Suspended)
                    {
                        if (_connectors.All(c => c.State == EmulationStates.Suspended))
                        {
                            SetIsEnabled(true, false, true);
                        }
                    }
                };

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

                    connector.NewMessage += message =>
                    {
                        if (message is QuoteChangeMessage quoteMsg)
                        {
                            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;
        }