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

                _connector = null;
                return;
            }

            // create test security
            var security = new Security
            {
                Id    = "RIU9@FORTS",
                Code  = "RIU9",
                Name  = "RTS-9.09",
                Board = ExchangeBoard.Forts,
            };

            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 })
            {
                MarketTimeChangedInterval = timeFrame
            };

            _logManager.Sources.Add(_connector);

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

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

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

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

            _connector.StartDate = startTime;
            _connector.StopDate  = stopTime;

            var candleManager = new CandleManager(_connector);

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

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

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

            _strategy.PnLChanged += () =>
            {
                var data = new EquityData
                {
                    Time  = _strategy.CurrentTime,
                    Value = _strategy.PnL,
                };

                this.GuiAsync(() => _curveItems.Add(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(LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime));
                        }
                        else
                        {
                            MessageBox.Show(LocalizedStrings.cancelled);
                        }
                    });
                }
                else if (_connector.State == EmulationStates.Started)
                {
                    // start strategy when emulation started
                    _strategy.Start();
                    candleManager.Start(series);
                }
            };

            if (_curveItems == null)
            {
                _curveItems = Curve.CreateCurve(_strategy.Name, Colors.DarkGreen);
            }
            else
            {
                _curveItems.Clear();
            }

            Report.IsEnabled = false;

            _startEmulationTime = DateTime.Now;

            // raise NewSecurities and NewPortfolio for full fill strategy properties
            _connector.Connect();
        }
Ejemplo n.º 2
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.Str3017
                }),

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

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

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

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

            // storage to historical data
            var storageRegistry = new StorageRegistry
            {
                // set historical path
                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 refresh step
            var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>();

            // set ProgressBar bounds
            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());	// 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 })
                {
                    StorageRegistry = storageRegistry,

                    MarketEmulator =
                    {
                        Settings                =
                        {
                            // set time frame is backtesting on candles
                            UseCandlesTimeFrame = emulationInfo.UseCandleTimeFrame,

                            // 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 = true,
                    CreateDepthFromOrdersLog  = emulationInfo.UseOrderLog,
                    CreateTradesFromOrdersLog = emulationInfo.UseOrderLog,
                };

                connector.StartDate = startTime;
                connector.StopDate  = stopTime;

                connector.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;
                    }

                    // fill level1 values
                    connector.SendOutMessage(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 historical data loading when connection established successfully and all data subscribed
                    connector.Start();
                };

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

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

                // 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(LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime));
                            }
                            else
                            {
                                MessageBox.Show(LocalizedStrings.cancelled);
                            }
                        });
                    }
                    else if (connector.State == EmulationStates.Started)
                    {
                        SetIsEnabled(true);

                        // start strategy when emulation started
                        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;

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