示例#1
0
        private void ChartUpdateTimerOnTick(object sender, EventArgs eventArgs)
        {
            if (IsRealtime.IsChecked == true && _lastPrice != 0m)
            {
                var nextTick = (ExecutionMessage)_tradeGenerator.Process(new TimeMessage {
                    ServerTime = _lastTime
                });

                if (nextTick != null)
                {
                    AppendTick(_security, nextTick);
                }

                _lastTime += TimeSpan.FromSeconds(10);
            }

            Tuple <TimeFrameCandle, bool>[] candlesToUpdate;
            lock (_updatedCandles.SyncRoot)
            {
                candlesToUpdate = _updatedCandles.OrderBy(p => p.Key).Select(p => p.Value).ToArray();
                _updatedCandles.Clear();
            }

            var lastCandle = _allCandles.LastOrDefault();

            _allCandles.AddRange(candlesToUpdate.Where(c => lastCandle == null || c.Item1.OpenTime != lastCandle.OpenTime).Select(t => t.Item1));

            ChartDrawData chartData = null;

            foreach (var tuple in candlesToUpdate)
            {
                var candle       = tuple.Item1;
                var needToFinish = tuple.Item2;

                if (chartData == null)
                {
                    chartData = new ChartDrawData();
                }

                if (needToFinish)
                {
                    candle.State = CandleStates.Finished;
                }

                var chartGroup = chartData.Group(candle.OpenTime);

                lock (candle.PriceLevels)
                    chartGroup.Add(_candleElement, candle);

                foreach (var pair in _indicators.CachedPairs)
                {
                    chartGroup.Add(pair.Key, pair.Value.Process(candle));
                }
            }

            if (chartData != null)
            {
                Chart.Draw(chartData);
            }
        }
示例#2
0
        private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator)
        {
            _dataThreadActions.Add(() =>
            {
                var oldReset = Chart.DisableIndicatorReset;
                try
                {
                    Chart.DisableIndicatorReset = true;
                    indicator.Reset();
                }
                finally
                {
                    Chart.DisableIndicatorReset = oldReset;
                }

                var chartData = new ChartDrawData();

                foreach (var candle in _allCandles.CachedValues)
                {
                    chartData.Group(candle.OpenTime).Add(element, indicator.Process(candle));
                }

                Chart.Reset(new[] { element });
                Chart.Draw(chartData);

                _indicators[element] = indicator;
            });
        }
        private void OnConnect()
        {
            _connector = new QuikTrader()
            {
                LuaFixServerAddress = "127.0.0.1:5002".To <EndPoint>()
            };
            SecurityEditor.SecurityProvider = _connector;
            _candleManager = new CandleManager(_connector);

            _connector.Connected += () =>
            {
                this.GuiAsync(() =>
                {
                    StatusTextBlock.Text  = "Соединение установлено!";
                    ConnectButtom.Content = "Разъединить";
                });
            };

            _connector.Disconnected += () =>
            {
                this.GuiAsync(() =>
                {
                    StatusTextBlock.Text  = "Соединение разорвано!";
                    ConnectButtom.Content = "Соединить";
                });
            };

            // Это обработчик событие получения свечи
            _candleManager.Processing += (series, candle) =>
            {
                if (series != _series)
                {
                    return;
                }

                // Используем только завершенные свечи
                if (candle.State != CandleStates.Finished)
                {
                    return;
                }

                // Рассчитываем значение индикатора
                var smaValue = _sma.Process(candle);

                // Создаем экземпляр класса ChartDrawData - класс, где группируются данные для отрисовки
                var data = new ChartDrawData();

                // chartItem - набор элементов, привязанных к одной точке на шкале X
                var chartItem = data.Group(candle.OpenTime).Add(_candleElement, candle);
                chartItem.Add(_indicatorElement, smaValue);

                // Безопасно отрисовываем элементы на графике
                this.GuiSync(() =>
                {
                    Chart.Draw(data);
                });
            };

            _connector.Connect();
        }
示例#4
0
        private void Chart_OnMoveOrder(Order order, decimal newPrice)
        {
            if (NeedToConfirm && !Confirm($"Move order to price={newPrice}?"))
            {
                var d = new ChartDrawData();
                // redraw order with old price
                d.Add(_activeOrdersElement, order);
                Chart.Draw(d);

                return;
            }

            var singleObject = UseSingleOrderObject;

            Log($"MoveOrder to {newPrice}: {order}, single order object = {singleObject}");

            if (IsInFinalState(order))
            {
                Log("invalid state for re-register");
                return;
            }

            if (singleObject)
            {
                Chart_OnMoveOrder1(order, newPrice);
            }
            else
            {
                Chart_OnMoveOrder2(order, newPrice);
            }
        }
        private void DrawChartElements()
        {
            var messages = _updatedCandles.SyncGet(uc => uc.CopyAndClear());

            if (messages.Length == 0)
            {
                return;
            }

            var lastTime        = DateTimeOffset.MinValue;
            var candlesToUpdate = new List <Candle>();

            foreach (var message in messages.Reverse())
            {
                if (lastTime == message.OpenTime)
                {
                    continue;
                }

                lastTime = message.OpenTime;

                if (_holder.UpdateCandle(message, out var candle) != null)
                {
                    if (candlesToUpdate.Count == 0 || candlesToUpdate.Last() != candle)
                    {
                        candlesToUpdate.Add(candle);
                    }
                }
            }

            candlesToUpdate.Reverse();

            foreach (var candle in candlesToUpdate)
            {
                _allCandles[candle.OpenTime] = candle;
            }

            ChartDrawData chartData = null;

            foreach (var candle in candlesToUpdate)
            {
                if (chartData == null)
                {
                    chartData = new ChartDrawData();
                }

                var chartGroup = chartData.Group(candle.OpenTime);
                chartGroup.Add(_candleElement, candle);

                foreach (var pair in _indicators.CachedPairs)
                {
                    chartGroup.Add(pair.Key, pair.Value.Process(candle));
                }
            }

            if (chartData != null)
            {
                Chart.Draw(chartData);
            }
        }
        private void FirstStrategy_NewMyTrade(MyTrade myTrade)
        {
            var data = new ChartDrawData();

            data.Group(myTrade.Trade.Time)
            .Add(_tradesElem, myTrade);
            Chart.Draw(data);
        }
示例#7
0
        private void ProcessCandle(Candle candle)
        {
            // strategy are stopping
            if (ProcessState == ProcessStates.Stopping)
            {
                CancelActiveOrders();
                return;
            }

            this.AddInfoLog(LocalizedStrings.Str3634Params.Put(candle.OpenTime, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, candle.TotalVolume, candle.Security));

            // process new candle
            var longValue  = LongSma.Process(candle);
            var shortValue = ShortSma.Process(candle);

            // calc new values for short and long
            var isShortLessThenLong = ShortSma.GetCurrentValue() < LongSma.GetCurrentValue();

            // crossing happened
            if (_isShortLessThenLong != isShortLessThenLong)
            {
                // if short less than long, the sale, otherwise buy
                var direction = isShortLessThenLong ? Sides.Sell : Sides.Buy;

                // calc size for open position or revert
                var volume = Position == 0 ? Volume : Position.Abs().Min(Volume) * 2;

                // calc order price as a close price + offset
                var price = candle.ClosePrice + ((direction == Sides.Buy ? Security.PriceStep : -Security.PriceStep) ?? 1);

                RegisterOrder(this.CreateOrder(direction, price, volume));

                // or revert position via market quoting
                //var strategy = new MarketQuotingStrategy(direction, volume);
                //ChildStrategies.Add(strategy);

                // store current values for short and long
                _isShortLessThenLong = isShortLessThenLong;
            }

            var trade = _myTrades.FirstOrDefault();

            _myTrades.Clear();

            var data = new ChartDrawData();

            data
            .Group(candle.OpenTime)
            .Add(_candlesElem, candle)
            .Add(_shortElem, shortValue)
            .Add(_longElem, longValue)
            .Add(_tradesElem, trade);

            _chart.Draw(data);
        }
示例#8
0
        private void DrawCandle(TimeFrameCandle candle)
        {
            var data  = new ChartDrawData();
            var group = data.Group(candle.OpenTime);

            group.Add(_candleElement, candle);

            if (_indicatorElement != null)
            {
                group.Add(_indicatorElement, _indicator.Process((double)candle.ClosePrice));
            }

            Chart.Draw(data);
        }
示例#9
0
        private void ProcessCandle(Candle candle)
        {
            var longValue  = candle.State == CandleStates.Finished ? _strategy.LongSma.Process(candle) : null;
            var shortValue = candle.State == CandleStates.Finished ? _strategy.ShortSma.Process(candle) : null;

            var chartData = new ChartDrawData();

            chartData
            .Group(candle.OpenTime)
            .Add(_candlesElem, candle)
            .Add(_longMaElem, longValue)
            .Add(_shortMaElem, shortValue);

            _chart.Draw(chartData);
        }
示例#10
0
        private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator)
        {
            var chartData = new ChartDrawData();

            foreach (var candle in _allCandles.Cache)
            {
                //if (candle.State != CandleStates.Finished)
                //	candle.State = CandleStates.Finished;

                chartData.Group(candle.OpenTime).Add(element, indicator.Process(candle));
            }

            Chart.Draw(chartData);

            _indicators.Add(element, indicator);
        }
示例#11
0
        private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator)
        {
            _dataThreadActions.Add(() =>
            {
                var chartData = new ChartDrawData();

                foreach (var candle in _allCandles.CachedValues)
                {
                    chartData.Group(candle.OpenTime).Add(element, indicator.Process(candle));
                }

                Chart.Reset(new[] { element });
                Chart.Draw(chartData);

                _indicators[element] = indicator;

                this.GuiAsync(() => CustomColors_Changed(null, null));
            });
        }
示例#12
0
        private void ChartUpdateTimerOnTick(object sender, EventArgs eventArgs)
        {
            if (IsRealtime.IsChecked == true && _lastPrice != 0m)
            {
                var step  = _priceStep;
                var price = Round(_lastPrice + (decimal)((RandomGen.GetDouble() - 0.5) * 5 * (double)step), step);
                AppendTick(_security, new ExecutionMessage
                {
                    ServerTime  = _lastTime,
                    TradePrice  = price,
                    TradeVolume = RandomGen.GetInt(50) + 1,
                    OriginSide  = Sides.Buy,
                });
                _lastTime += TimeSpan.FromSeconds(10);
            }

            TimeFrameCandle[] candlesToUpdate;
            lock (_updatedCandles.SyncRoot)
            {
                candlesToUpdate = _updatedCandles.OrderBy(p => p.Key).Select(p => p.Value).ToArray();
                _updatedCandles.Clear();
            }

            var lastCandle = _allCandles.LastOrDefault();

            _allCandles.AddRange(candlesToUpdate.Where(c => lastCandle == null || c.OpenTime != lastCandle.OpenTime));

            var hasValue  = false;
            var chartData = new ChartDrawData();

            foreach (var candle in candlesToUpdate)
            {
                chartData.Group(candle.OpenTime).Add(_candleElement1, candle);
                hasValue = true;
            }

            if (hasValue)
            {
                Chart.Draw(chartData);
            }
        }
示例#13
0
        private void CustomColors2_Changed(object sender, RoutedEventArgs e)
        {
            var colored = CustomColors2.IsChecked == true;

            _drawWithColor = colored;
            _dataThreadActions.Add(() =>
            {
                if (_allCandles.IsEmpty())
                {
                    return;
                }

                var dd = new ChartDrawData();
                foreach (var c in _allCandles)
                {
                    dd.Group(c.Value.OpenTime).Add(_candleElement, colored ? GetRandomColor() : (Color?)null);
                }

                Chart.Draw(dd);
            });
        }
示例#14
0
        private void ChartUpdateTimerOnTick(object sender, EventArgs eventArgs)
        {
            TimeFrameCandle[] candlesToUpdate;

            lock (_updatedCandles.SyncRoot)
            {
                candlesToUpdate = _updatedCandles.OrderBy(p => p.Key).Select(p => p.Value).ToArray();
                _updatedCandles.Clear();
            }

            var lastCandle = _allCandles.LastOrDefault();

            _allCandles.AddRange(candlesToUpdate.Where(c => lastCandle == null || c.OpenTime != lastCandle.OpenTime));

            var data = new ChartDrawData();

            foreach (var candle in candlesToUpdate)
            {
                data.Group(candle.OpenTime).Add(_candleElement, candle);
            }

            Chart.Draw(data);
        }
示例#15
0
        private void ModifyAnnotation(bool isNew)
        {
            Brush RandomBrush()
            {
                var b = new SolidColorBrush(Color.FromRgb((byte)RandomGen.GetInt(0, 255), (byte)RandomGen.GetInt(0, 255), (byte)RandomGen.GetInt(0, 255)));

                b.Freeze();
                return(b);
            }

            if (_annotation == null)
            {
                return;
            }

            IComparable x1, x2, y1, y2;

            var mode = RandomGen.GetDouble() > 0.5 ? AnnotationCoordinateMode.Absolute : AnnotationCoordinateMode.Relative;

            if (_annotationData == null)
            {
                if (mode == AnnotationCoordinateMode.Absolute)
                {
                    GetMiddle(out var x0, out var y0);
                    x1 = x0 - TimeSpan.FromMinutes(RandomGen.GetInt(10, 60));
                    x2 = x0 + TimeSpan.FromMinutes(RandomGen.GetInt(10, 60));
                    y1 = y0 - RandomGen.GetInt(5, 10) * _security.PriceStep ?? 0.01m;
                    y2 = y0 + RandomGen.GetInt(5, 10) * _security.PriceStep ?? 0.01m;
                }
                else
                {
                    x1 = 0.5 - RandomGen.GetDouble() / 10;
                    x2 = 0.5 + RandomGen.GetDouble() / 10;
                    y1 = 0.5 - RandomGen.GetDouble() / 10;
                    y2 = 0.5 - RandomGen.GetDouble() / 10;
                }
            }
            else
            {
                mode = _annotationData.CoordinateMode.Value;

                if (mode == AnnotationCoordinateMode.Absolute)
                {
                    x1 = (DateTimeOffset)_annotationData.X1 - TimeSpan.FromMinutes(1);
                    x2 = (DateTimeOffset)_annotationData.X2 + TimeSpan.FromMinutes(1);
                    y1 = (decimal)_annotationData.Y1 + _security.PriceStep ?? 0.01m;
                    y2 = (decimal)_annotationData.Y2 - _security.PriceStep ?? 0.01m;
                }
                else
                {
                    x1 = ((double)_annotationData.X1) - 0.05;
                    x2 = ((double)_annotationData.X2) + 0.05;
                    y1 = ((double)_annotationData.Y1) - 0.05;
                    y2 = ((double)_annotationData.Y2) + 0.05;
                }
            }

            _dataThreadActions.Add(() =>
            {
                var data = new ChartDrawData.AnnotationData
                {
                    X1         = x1,
                    X2         = x2,
                    Y1         = y1,
                    Y2         = y2,
                    IsVisible  = true,
                    Fill       = RandomBrush(),
                    Stroke     = RandomBrush(),
                    Foreground = RandomBrush(),
                    Thickness  = new Thickness(RandomGen.GetInt(1, 5)),
                };

                if (isNew)
                {
                    data.Text = "random annotation #" + (++_annotationId);
                    data.HorizontalAlignment = HorizontalAlignment.Stretch;
                    data.VerticalAlignment   = VerticalAlignment.Stretch;
                    data.LabelPlacement      = LabelPlacement.Axis;
                    data.ShowLabel           = true;
                    data.CoordinateMode      = mode;
                }

                var dd = new ChartDrawData();
                dd.Add(_annotation, data);

                Chart.Draw(dd);
            });
        }
示例#16
0
        private void ChartUpdateTimerOnTick(object sender, EventArgs eventArgs)
        {
            if (_historyLoaded && IsRealtime.IsChecked == true)
            {
                var nextTick = (ExecutionMessage)_tradeGenerator.Process(new TimeMessage {
                    ServerTime = _lastTime
                });

                if (nextTick != null)
                {
                    if (_candleTransform.Process(nextTick))
                    {
                        var candles = _candleBuilder.Process(_mdMsg, _currCandle, _candleTransform);

                        lock (_lock)
                        {
                            foreach (var candle in candles)
                            {
                                _currCandle = candle;
                                _updatedCandles[candle.OpenTime] = Tuple.Create(candle, candle.State == CandleStates.Finished);
                            }
                        }
                    }
                }

                _lastTime += TimeSpan.FromSeconds(RandomGen.GetInt(1, 10));
            }

            Tuple <Candle, bool>[] candlesToUpdate;
            lock (_updatedCandles.SyncRoot)
            {
                candlesToUpdate = _updatedCandles.OrderBy(p => p.Key).Select(p => Tuple.Create(p.Value.Item1.ToCandle(_security), p.Value.Item2)).ToArray();
                _updatedCandles.Clear();
            }

            var lastCandle = _allCandles.LastOrDefault();

            _allCandles.AddRange(candlesToUpdate.Where(c => lastCandle == null || c.Item1.OpenTime != lastCandle.OpenTime).Select(t => t.Item1));

            ChartDrawData chartData = null;

            foreach (var tuple in candlesToUpdate)
            {
                var candle       = tuple.Item1;
                var needToFinish = tuple.Item2;

                if (chartData == null)
                {
                    chartData = new ChartDrawData();
                }

                if (needToFinish && candle.State != CandleStates.Finished)
                {
                    candle.State = CandleStates.Finished;
                }

                var chartGroup = chartData.Group(candle.OpenTime);

                lock (_lock)
                {
                    chartGroup.Add(_candleElement, candle);
                }

                foreach (var pair in _indicators.CachedPairs)
                {
                    chartGroup.Add(pair.Key, pair.Value.Process(candle));
                }
            }

            if (chartData != null)
            {
                Chart.Draw(chartData);
            }
        }
示例#17
0
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            if (HistoryPath.Folder.IsEmpty() || !Directory.Exists(HistoryPath.Folder))
            {
                MessageBox.Show(this, LocalizedStrings.Str3014);
                return;
            }

            if (Math.Abs(TestingProcess.Value - 0) > double.Epsilon)
            {
                MessageBox.Show(this, LocalizedStrings.Str3015);
                return;
            }

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

            logManager.Listeners.Add(fileLogListener);

            // SMA periods
            var periods = new[]
            {
                new Tuple <int, int, Color>(80, 10, Colors.DarkGreen),
                new Tuple <int, int, Color>(70, 8, Colors.Red),
                new Tuple <int, int, Color>(60, 6, Colors.DarkBlue)
            };

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

            var timeFrame = TimeSpan.FromMinutes(5);

            // create test security
            var security = new Security
            {
                Id    = "RIZ2@FORTS",              // sec id has the same name as folder with historical data
                Code  = "RIZ2",
                Name  = "RTS-12.12",
                Board = ExchangeBoard.Forts,
            };

            var startTime = new DateTime(2012, 10, 1);
            var stopTime  = new DateTime(2012, 10, 31);

            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 batchEmulation = new BatchEmulation(new[] { security }, new[] { portfolio }, storageRegistry)
            {
                EmulationSettings =
                {
                    MarketTimeChangedInterval = timeFrame,
                    StartTime = startTime,
                    StopTime  = stopTime,

                    // count of parallel testing strategies
                    BatchSize                 = periods.Length,
                }
            };

            // handle historical time for update ProgressBar
            batchEmulation.ProgressChanged += (curr, total) => this.GuiAsync(() => TestingProcess.Value = total);

            batchEmulation.StateChanged += (oldState, newState) =>
            {
                if (batchEmulation.State != EmulationStates.Stopped)
                {
                    return;
                }

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

            // get emulation connector
            var connector = batchEmulation.EmulationConnector;

            logManager.Sources.Add(connector);

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

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

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

            _startEmulationTime = DateTime.Now;

            var strategies = periods
                             .Select(period =>
            {
                var candleManager = new CandleManager(connector);
                var series        = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);

                // create strategy based SMA
                var strategy = new SmaStrategy(candleManager, series, new SimpleMovingAverage {
                    Length = period.Item1
                }, new SimpleMovingAverage {
                    Length = period.Item2
                })
                {
                    Volume    = 1,
                    Security  = security,
                    Portfolio = portfolio,
                    Connector = connector,

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

                strategy.SetCandleManager(candleManager);

                var curveElem = Curve.CreateCurve(LocalizedStrings.Str3026Params.Put(period.Item1, period.Item2), period.Item3, ChartIndicatorDrawStyles.Line);

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

                    data
                    .Group(strategy.CurrentTime)
                    .Add(curveElem, strategy.PnL);

                    Curve.Draw(data);
                };

                Stat.AddStrategies(new[] { strategy });

                return(strategy);
            });

            // start emulation
            batchEmulation.Start(strategies, periods.Length);
        }
示例#18
0
        private void LoadData()
        {
            _lastPrice = 0m;

            _candles.Clear();
            var id = _securityId.ToSecurityId();

            _security = new Security
            {
                Id        = _securityId,
                PriceStep = _priceStep,
                Board     = _exchangeInfoProvider.GetExchangeBoard(id.BoardCode) ?? ExchangeBoard.Associated
            };

            Chart.Reset(new IChartElement[] { _candleElement });

            var storage = new StorageRegistry();

            var maxDays = 50;

            //BusyIndicator.IsBusy = true;

            var path = _historyPath;

            _curCandleNum = 0;

            Task.Factory.StartNew(() =>
            {
                var date = DateTime.MinValue;

                foreach (var tick in storage.GetTickMessageStorage(_security, new LocalMarketDataDrive(path)).Load())
                {
                    if (date != tick.ServerTime.Date)
                    {
                        date = tick.ServerTime.Date;

                        //var str = $"Loading ticks for {date:dd MMM yyyy}...";
                        //this.GuiAsync(() => BusyIndicator.BusyContent = str);

                        if (--maxDays == 0)
                        {
                            break;
                        }
                    }

                    AppendTick(tick);
                }
            })
            .ContinueWith(t =>
            {
                //this.GuiAsync(() => BusyIndicator.IsBusy = false);

                for (var i = 0; i < _candles.Count; i += _candlesPacketSize)
                {
                    var data = new ChartDrawData();

                    var candles = _candles.GetRange(i, Math.Min(_candlesPacketSize, _candles.Count - i)).Select(c => c.ToCandle(_tfSpan, _security));

                    foreach (var candle in candles)
                    {
                        candle.State = CandleStates.Finished;

                        var group = data.Group(candle.OpenTime);

                        group.Add(_candleElement, candle);

                        if (_indicatorElement != null)
                        {
                            group.Add(_indicatorElement, _indicator.Process((double)candle.ClosePrice));
                        }
                    }

                    Chart.Draw(data);
                }
            })
            .ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    Error(t.Exception.Message);
                }

                _dataIsLoaded = true;

                //this.GuiAsync(() => BusyIndicator.IsBusy = false);

                Chart.IsAutoRange = false;
                //_area.YAxises.FirstOrDefault().Do(a => a.AutoRange = false);
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
示例#19
0
        private void DrawChartElements()
        {
            var messages = _updatedCandles.SyncGet(uc => uc.CopyAndClear());

            if (messages.Length == 0)
            {
                return;
            }

            var lastTime        = DateTimeOffset.MinValue;
            var candlesToUpdate = new List <Candle>();

            foreach (var message in messages.Reverse())
            {
                if (lastTime == message.OpenTime)
                {
                    continue;
                }

                lastTime = message.OpenTime;

                var info = _holder.UpdateCandles(_transactionId, message);

                if (info == null)
                {
                    continue;
                }

                var candle = info.Item2;

                if (candlesToUpdate.Count == 0 || candlesToUpdate.Last() != candle)
                {
                    candlesToUpdate.Add(candle);
                }
            }

            candlesToUpdate.Reverse();

            foreach (var candle in candlesToUpdate)
            {
                _allCandles[candle.OpenTime] = candle;
            }

            ChartDrawData chartData = null;

            foreach (var candle in candlesToUpdate)
            {
                if (chartData == null)
                {
                    chartData = new ChartDrawData();
                }

                if (_lastCandleDrawTime != candle.OpenTime)
                {
                    _lastCandleDrawTime = candle.OpenTime;
                    _candleDrawColor    = GetRandomColor();
                }

                var chartGroup = chartData.Group(candle.OpenTime);
                chartGroup.Add(_candleElement, candle);
                chartGroup.Add(_candleElement, _drawWithColor ? _candleDrawColor : (Color?)null);

                foreach (var pair in _indicators.CachedPairs)
                {
                    chartGroup.Add(pair.Key, pair.Value.Process(candle));
                }
            }

            if (chartData != null)
            {
                Chart.Draw(chartData);
            }
        }
示例#20
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();
        }
示例#21
0
        private void Chart_OnMoveOrder(Order oldOrder, decimal newPrice)
        {
            if (NeedToConfirm && !Confirm($"Move order to price={newPrice}?"))
            {
                var d = new ChartDrawData();
                d.Add(_activeOrdersElement, oldOrder);
                Chart.Draw(d);

                return;
            }

            Log($"MoveOrder to {newPrice}: {oldOrder}");

            if (IsInFinalState(oldOrder))
            {
                Log("invalid state for re-register");
                return;
            }

            var newOrder = new OrderEx
            {
                TransactionId = _idGenerator.GetNextId(),
                Type          = OrderTypes.Limit,
                State         = OrderStates.Pending,
                Price         = newPrice,
                Volume        = oldOrder.Balance,
                Direction     = oldOrder.Direction,
                Balance       = oldOrder.Balance,
                Security      = oldOrder.Security,
                Portfolio     = oldOrder.Portfolio,
            };

            Chart.Draw(new ChartDrawData()
                       .Add(_activeOrdersElement, oldOrder, true, price: newOrder.Price));

            void MoveAction()
            {
                if (NeedToFail)
                {
                    Log("Move failed");

                    newOrder.State = OrderStates.Failed;

                    Chart.Draw(new ChartDrawData()
                               .Add(_activeOrdersElement, oldOrder, isError: true, price: oldOrder.Price));
                }
                else
                {
                    oldOrder.State = OrderStates.Done;
                    newOrder.State = OrderStates.Active;

                    Log($"Order moved to new: {newOrder}");

                    Chart.Draw(new ChartDrawData()
                               .Add(_activeOrdersElement, oldOrder)
                               .Add(_activeOrdersElement, newOrder));

                    _orders.Remove(oldOrder);
                    _orders.Add(newOrder);
                }
            }

            if (NeedToDelay)
            {
                DelayedAction(MoveAction, "move");
            }
            else
            {
                MoveAction();
            }
        }
示例#22
0
        private void StartBtnClick(object sender, RoutedEventArgs e)
        {
            if (_batchEmulation != null)
            {
                _batchEmulation.Resume();
                return;
            }

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

            TestingProcess.Value = 0;
            Curve.Clear();
            Stat.Clear();

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

            logManager.Listeners.Add(fileLogListener);

            // SMA periods
            var periods = new List <(int longMa, int shortMa, Color color)>();

            for (var l = 100; l >= 50; l -= 10)
            {
                for (var s = 10; s >= 5; s -= 1)
                {
                    periods.Add((l, s, Color.FromRgb((byte)RandomGen.GetInt(255), (byte)RandomGen.GetInt(255), (byte)RandomGen.GetInt(255))));
                }
            }

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

            var timeFrame = TimeSpan.FromMinutes(1);

            // create test security
            var security = new Security
            {
                Id    = "SBER@TQBR",              // sec id has the same name as folder with historical data
                Code  = "SBER",
                Name  = "SBER",
                Board = ExchangeBoard.Micex,
            };

            var startTime = new DateTime(2020, 4, 1);
            var stopTime  = new DateTime(2020, 4, 20);

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

            // test portfolio
            var portfolio = Portfolio.CreateSimulator();

            // create backtesting connector
            _batchEmulation = new BatchEmulation(new[] { security }, new[] { portfolio }, storageRegistry)
            {
                EmulationSettings =
                {
                    MarketTimeChangedInterval = timeFrame,
                    StartTime = startTime,
                    StopTime  = stopTime,

                    // count of parallel testing strategies
                    // if not set, then CPU count * 2
                    //BatchSize = 3,
                }
            };

            // handle historical time for update ProgressBar
            _batchEmulation.TotalProgressChanged += (currBatch, total) => this.GuiAsync(() => TestingProcess.Value = total);

            _batchEmulation.StateChanged += (oldState, newState) =>
            {
                var isFinished = _batchEmulation.IsFinished;

                if (_batchEmulation.State == ChannelStates.Stopped)
                {
                    _batchEmulation = null;
                }

                this.GuiAsync(() =>
                {
                    switch (newState)
                    {
                    case ChannelStates.Stopping:
                    case ChannelStates.Starting:
                    case ChannelStates.Suspending:
                        SetIsEnabled(false, false, false);
                        break;

                    case ChannelStates.Stopped:
                        SetIsEnabled(true, false, false);

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

                        break;

                    case ChannelStates.Started:
                        SetIsEnabled(false, true, true);
                        break;

                    case ChannelStates.Suspended:
                        SetIsEnabled(true, false, true);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(newState.ToString());
                    }
                });
            };

            _startEmulationTime = DateTime.Now;

            var strategies = periods
                             .Select(period =>
            {
                var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);

                // create strategy based SMA
                var strategy = new SampleHistoryTesting.SmaStrategy(series)
                {
                    ShortSma = { Length = period.shortMa },
                    LongSma  = { Length = period.longMa },

                    Volume    = 1,
                    Security  = security,
                    Portfolio = portfolio,
                    //Connector = connector,

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

                this.GuiSync(() =>
                {
                    var curveElem = Curve.CreateCurve(LocalizedStrings.Str3026Params.Put(period.Item1, period.Item2), period.Item3, ChartIndicatorDrawStyles.Line);

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

                        data
                        .Group(strategy.CurrentTime)
                        .Add(curveElem, strategy.PnL);

                        Curve.Draw(data);
                    };

                    Stat.AddStrategies(new[] { strategy });
                });

                return(strategy);
            });

            // start emulation
            _batchEmulation.Start(strategies, periods.Count);
        }
示例#23
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,
            };

            // 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,
                    CustomHistoryAdapter = g => new FinamMessageAdapter(g),
                    CurveColor           = Colors.DarkBlue,
                    StrategyName         = LocalizedStrings.FinamCandles
                },
                    FinamCandlesChart,
                    FinamCandlesEquity,
                    FinamCandlesPosition),

                Tuple.Create(
                    YahooCandlesCheckBox,
                    YahooCandlesProgress,
                    YahooCandlesParameterGrid,
                    // candles
                    new EmulationInfo
                {
                    UseCandleTimeFrame   = timeFrame,
                    CustomHistoryAdapter = g => new YahooMessageAdapter(g),
                    CurveColor           = Colors.DarkBlue,
                    StrategyName         = LocalizedStrings.YahooCandles
                },
                    YahooCandlesChart,
                    YahooCandlesEquity,
                    YahooCandlesPosition),

                Tuple.Create(
                    RandomCheckBox,
                    RandomProgress,
                    RandomParameterGrid,
                    // candles
                    new EmulationInfo
                {
                    UseCandleTimeFrame   = timeFrame,
                    CustomHistoryAdapter = g => new OwnMessageAdapter(g),
                    CurveColor           = Colors.DarkBlue,
                    StrategyName         = LocalizedStrings.Custom
                },
                    RandomChart,
                    RandomEquity,
                    RandomPosition),
            };

            // 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 = Portfolio.CreateSimulator();

                var secProvider = (ISecurityProvider) new CollectionSecurityProvider(new[] { security });

                // create backtesting connector
                var connector = new HistoryEmulationConnector(
                    secProvider, 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,

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

                if (emulationInfo.CustomHistoryAdapter != null)
                {
                    connector.Adapter.InnerAdapters.Remove(connector.MarketDataAdapter);
                    connector.Adapter.InnerAdapters.Add(new CustomHistoryMessageAdapter(emulationInfo.CustomHistoryAdapter(connector.TransactionIdGenerator), secProvider));
                }

                // set history range
                connector.HistoryMessageAdapterEx.StartDate = startTime;
                connector.HistoryMessageAdapterEx.StopDate  = stopTime;

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

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

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

                        if (
                            // if order book will be generated
                            generateDepths ||
                            // or 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.SubscribeOrderLog(security);
                    }

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

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

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

                    // 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)
                    {
                        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;
        }
示例#24
0
        private void ProcessCandle(Candle candle)
        {
            // strategy are stopping
            if (ProcessState == ProcessStates.Stopping)
            {
                CancelActiveOrders();
                return;
            }

            this.AddInfoLog(LocalizedStrings.Str3634Params.Put(candle.OpenTime, candle.OpenPrice, candle.HighPrice, candle.LowPrice, candle.ClosePrice, candle.TotalVolume, candle.Security));

            // process new candle
            var longValue  = LongSma.Process(candle);
            var shortValue = ShortSma.Process(candle);

            // calc new values for short and long
            var isShortLessThenLong = ShortSma.GetCurrentValue() < LongSma.GetCurrentValue();

            // crossing happened
            if (_isShortLessThenLong != isShortLessThenLong)
            {
                // if short less than long, the sale, otherwise buy
                var direction = isShortLessThenLong ? Sides.Sell : Sides.Buy;

                // calc size for open position or revert
                var volume = Position == 0 ? Volume : Position.Abs().Min(Volume) * 2;

                if (!SafeGetConnector().RegisteredMarketDepths.Contains(Security))
                {
                    var price = Security.GetMarketPrice(Connector, direction);

                    // register "market" order (limit order with guaranteed execution price)
                    if (price != null)
                    {
                        RegisterOrder(this.CreateOrder(direction, price.Value, volume));
                    }
                }
                else
                {
                    // register order (limit order)
                    RegisterOrder(this.CreateOrder(direction, (decimal)(Security.GetCurrentPrice(this, direction) ?? 0), volume));

                    // or revert position via market quoting
                    //var strategy = new MarketQuotingStrategy(direction, volume)
                    //{
                    //	WaitAllTrades = true,
                    //};
                    //ChildStrategies.Add(strategy);
                }

                // store current values for short and long
                _isShortLessThenLong = isShortLessThenLong;
            }

            var trade = _myTrades.FirstOrDefault();

            _myTrades.Clear();

            var data = new ChartDrawData();

            data
            .Group(candle.OpenTime)
            .Add(_candlesElem, candle)
            .Add(_shortElem, shortValue)
            .Add(_longElem, longValue)
            .Add(_tradesElem, trade);

            _chart.Draw(data);
        }