protected override void InitExample()
        {
            var dataSeries      = new XyzDataSeries <DateTime, double, double>();
            var tradeDataSource = DataManager.Instance.GetTradeticks().ToArray();

            dataSeries.Append(
                tradeDataSource.Select(x => x.TradeDate),
                tradeDataSource.Select(x => x.TradePrice),
                tradeDataSource.Select(x => x.TradeSize));

            var xAxis = new DateAxis(Activity)
            {
                GrowBy = new DoubleRange(0, 0.1)
            };
            var yAxis = new NumericAxis(Activity)
            {
                GrowBy = new DoubleRange(0, 0.1)
            };

            var lineSeries = new FastLineRenderableSeries
            {
                DataSeries  = dataSeries,
                StrokeStyle = new PenStyle.Builder(Activity).WithColor(Color.Rgb(0xFF, 0x33, 0x33))
                              .WithThickness(1f, ComplexUnitType.Dip).Build()
            };

            var stops        = new[] { 0, 0.95f, 1 };
            var colors       = new int[] { Color.Transparent, Resources.GetColor(Resource.Color.color_primary), Color.Transparent };
            var gradientFill = new RadialGradientBrushStyle(0.5f, 0.5f, 0.5f, 0.5f, colors, stops, TileMode.Clamp);

            var bubbleSeries = new FastBubbleRenderableSeries
            {
                DataSeries       = dataSeries,
                BubbleBrushStyle = gradientFill,
                ZScaleFactor     = 3,
                AutoZRange       = false,
            };

            using (Surface.SuspendUpdates())
            {
                Surface.XAxes.Add(xAxis);
                Surface.YAxes.Add(yAxis);
                Surface.RenderableSeries.Add(lineSeries);
                Surface.RenderableSeries.Add(bubbleSeries);

                Surface.ChartModifiers = new ChartModifierCollection
                {
                    new RubberBandXyZoomModifier(),
                    new ZoomExtentsModifier(),
                };
            }
        }
        public ScatterSeriesTernaryChartExampleView()
        {
            InitializeComponent();

            _random = new FasterRandom();

            // scatters series
            var scatterDataSeries1 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Substance A"
            };
            var scatterDataSeries2 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Substance B"
            };
            var scatterDataSeries3 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Substance C"
            };

            // Air series
            for (int i = 0; i < 75; i++)
            {
                var x = _random.Next(0, 50);
                var z = _random.Next(20, 40);
                var y = 100 - (x + z);
                scatterDataSeries1.Append(x, y, z);
            }

            // Earth series
            for (int i = 0; i < 75; i++)
            {
                var x = _random.Next(0, 40);
                var z = _random.Next(0, 20);
                var y = 100 - (x + z);
                scatterDataSeries2.Append(x, y, z);
            }

            // Fire series
            for (int i = 0; i < 75; i++)
            {
                var x = _random.Next(20, 40);
                var y = _random.Next(0, 25);
                var z = 100 - (x + y);
                scatterDataSeries3.Append(x, y, z);
            }

            scatterSeries1.DataSeries = scatterDataSeries1;
            scatterSeries2.DataSeries = scatterDataSeries2;
            scatterSeries3.DataSeries = scatterDataSeries3;
        }
Example #3
0
        protected override void InitExample()
        {
            var xAxis = new SCIDateTimeAxis {
                GrowBy = new SCIDoubleRange(0.0, 0.1)
            };
            var yAxis = new SCINumericAxis {
                GrowBy = new SCIDoubleRange(0, 0.1)
            };

            var dataSeries      = new XyzDataSeries <DateTime, double, double>();
            var tradeDataSource = DataManager.Instance.GetTradeticks().ToArray();

            dataSeries.Append(
                tradeDataSource.Select(x => x.TradeDate).ToArray(),
                tradeDataSource.Select(x => x.TradePrice).ToArray(),
                tradeDataSource.Select(x => x.TradeSize).ToArray());

            var lineSeries = new SCIFastLineRenderableSeries
            {
                DataSeries  = dataSeries,
                StrokeStyle = new SCISolidPenStyle(0xFFFF3333, 1f)
            };

            var bubbleSeries = new SCIBubbleRenderableSeries
            {
                DataSeries = dataSeries,
                //Style = new SCIBubbleSeriesStyle { Detalization = 40,  },
                ZScaleFactor     = 1,
                AutoZRange       = false,
                BubbleBrushStyle = new SCISolidBrushStyle(0x50CCCCCC),
                StrokeStyle      = new SCISolidPenStyle(0x90CCCCCC, 2f)
            };

            using (Surface.SuspendUpdates())
            {
                Surface.XAxes.Add(xAxis);
                Surface.YAxes.Add(yAxis);
                Surface.RenderableSeries.Add(lineSeries);
                Surface.RenderableSeries.Add(bubbleSeries);

                Surface.ChartModifiers = new SCIChartModifierCollection
                {
                    new SCIZoomPanModifier(),
                    new SCIPinchZoomModifier(),
                    new SCIZoomExtentsModifier()
                };
            }
        }
        protected override void InitExample()
        {
            var xAxis = new DateAxis(Activity)
            {
                GrowBy = new DoubleRange(0, 0.1)
            };
            var yAxis = new NumericAxis(Activity)
            {
                GrowBy = new DoubleRange(0, 0.1)
            };

            var dataSeries      = new XyzDataSeries <DateTime, double, double>();
            var tradeDataSource = DataManager.Instance.GetTradeticks().ToArray();

            dataSeries.Append(
                tradeDataSource.Select(x => x.TradeDate),
                tradeDataSource.Select(x => x.TradePrice),
                tradeDataSource.Select(x => x.TradeSize));

            var lineSeries = new FastLineRenderableSeries
            {
                DataSeries  = dataSeries,
                StrokeStyle = new SolidPenStyle(0xFFFF3333, 1.ToDip(Activity))
            };

            var bubbleSeries = new FastBubbleRenderableSeries
            {
                DataSeries       = dataSeries,
                BubbleBrushStyle = new SolidBrushStyle(0x77CCCCCC),
                StrokeStyle      = new SolidPenStyle(0xFFCCCCCC, 2f.ToDip(Activity)),
                ZScaleFactor     = 3,
                AutoZRange       = false,
            };

            using (Surface.SuspendUpdates())
            {
                Surface.XAxes.Add(xAxis);
                Surface.YAxes.Add(yAxis);
                Surface.RenderableSeries.Add(lineSeries);
                Surface.RenderableSeries.Add(bubbleSeries);
                Surface.ChartModifiers = new ChartModifierCollection
                {
                    new RubberBandXyZoomModifier(),
                    new ZoomExtentsModifier(),
                };
            }
        }
Example #5
0
        private void AppendPoint(double sampleRate)
        {
            if (_currentIndex >= _sourceData.Length)
            {
                _currentIndex = 0;
            }

            // Get the next voltage and time, and append to the chart
            double voltage    = _sourceData[_currentIndex];
            double actualTime = (_totalIndex / sampleRate);
            double time       = actualTime % 10;

            const int MaxDataSeriesCount = 4000;

            if (_dataSeriesA.Count < MaxDataSeriesCount)
            {
                // For the first N points we append time, voltage, actual time
                // Time must be ascending in X for scichart to perform the best, so we clip this to 0-10s
                _dataSeriesA.Append(time, voltage, actualTime);
            }
            else
            {
                _dataSeriesIndex = _dataSeriesIndex >= MaxDataSeriesCount ? 0 : _dataSeriesIndex;

                // For subsequent points (after reaching the edge of the trace) we wrap traces around
                // We re-use the same data-series just update its Y,Z values then trigger a redraw
                _dataSeriesA.YValues[_dataSeriesIndex] = voltage;
                _dataSeriesA.ZValues[_dataSeriesIndex] = actualTime;
                _dataSeriesA.InvalidateParentSurface(RangeMode.None, hasDataChanged: true);

                //_dataSeriesA.OutputCsv();
            }

            // Update the position of the latest Trace annotation
            latestTrace.X1 = time;
            latestTrace.Y1 = voltage;

            // Update the DataSeries.Tag, used by PaletteProvider to dim the trace as time passes
            _dataSeriesA.Tag = time;

            _currentIndex++;
            _totalIndex++;
            _dataSeriesIndex++;
        }
        private void OnSciChartLoaded(object sender, RoutedEventArgs e)
        {
            // Add a data series to contain Xyy data. We want to use X,Y = position and Y1 = trade size
            var dataSeries = new XyzDataSeries <DateTime, double, double>();

            // Load the TradeTicks.csv file
            var tradeDataSource = DataManager.Instance.GetTradeticks().ToArray();

            // Append data to series. SciChart automatically redraws
            dataSeries.Append(tradeDataSource.Select(x => x.TradeDate),
                              tradeDataSource.Select(x => x.TradePrice),
                              tradeDataSource.Select(x => x.TradeSize));

            // XyzDataSeries is shared across two RenderableSeries
            //  - FastLineRenderableSeries chooses X,Y value to draw
            //  - FastBubbleRenderableSeries chooses X,Y value for position, Z for size
            lineSeries.DataSeries   = dataSeries as IXyzDataSeries;
            bubbleSeries.DataSeries = dataSeries;

            sciChart.ZoomExtents();
        }
        public TimeLineControl()
        {
            InitializeComponent();

            var xyData0 = new XyzDataSeries <double, double, int>();
            var xyData1 = new XyzDataSeries <double, double, int>();

            double iLast = 0;

            for (int i = 0; i < 100; i++)
            {
                // Parameters. We use X= startX, Y= length, Z= Color of fill
                double length = _random.Next(1, 10);
                xyData0.Append(iLast, length, GetRandomColor());
                xyData1.Append(iLast, length, GetRandomColor());
                iLast += length;
            }

            TimelineSeries0.DataSeries = xyData0;
            TimelineSeries1.DataSeries = xyData0;
        }
Example #8
0
        /// <summary>
        /// To analyze.
        /// </summary>
        protected override void OnAnalyze()
        {
            var chart = Chart;
            var grid  = Grid;

            var chartSeries = new XyzDataSeries <DateTime, double, double>();
            ThreadSafeObservableCollection <GridRow> gridSeries = null;

            chart.GuiSync(() =>
            {
                // clear prev values
                chart.RenderableSeries.Clear();
                grid.Columns.Clear();

                chart.RenderableSeries.Add(new FastBubbleRenderableSeries
                {
                    ResamplingMode = ResamplingMode.Auto,
                    BubbleColor    = Colors.Chocolate,
                    ZScaleFactor   = 0.1,
                    AutoZRange     = true,
                    DataSeries     = chartSeries
                });

                chart.XAxis = new DateTimeAxis {
                    GrowBy = new DoubleRange(0.0, 0.1)
                };
                chart.YAxis = new NumericAxis {
                    GrowBy = new DoubleRange(0.1, 0.1)
                };

                grid.AddTextColumn("Time", LocalizedStrings.Time).Width = 150;
                var volumeColumn   = grid.AddTextColumn("Volume", LocalizedStrings.Volume);
                volumeColumn.Width = 100;

                var gridSource   = new ObservableCollectionEx <GridRow>();
                grid.ItemsSource = gridSource;
                gridSeries       = new ThreadSafeObservableCollection <GridRow>(gridSource);

                grid.SetSort(volumeColumn, ListSortDirection.Descending);
            });

            // get candle storage
            var storage = StorateRegistry.GetCandleStorage(typeof(TimeFrameCandle), Security, TimeFrame, format: StorageFormat);

            // get available dates for the specified period
            var dates = storage.GetDates(From, To).ToArray();

            var rows = new Dictionary <TimeSpan, GridRow>();

            foreach (var loadDate in dates)
            {
                // check if stopped
                if (ProcessState != ProcessStates.Started)
                {
                    break;
                }

                // load candles
                var candles = storage.Load(loadDate);

                // groupping candles by open time
                var groupedCandles = candles.GroupBy(c => c.OpenTime.TimeOfDay.Truncate(TimeSpan.FromHours(1)));

                foreach (var group in groupedCandles.OrderBy(g => g.Key))
                {
                    // check if stopped
                    if (ProcessState != ProcessStates.Started)
                    {
                        break;
                    }

                    var time = group.Key;

                    // calc total volume for the specified time frame
                    var sumVol = group.Sum(c => c.TotalVolume);

                    var row = rows.TryGetValue(time);
                    if (row == null)
                    {
                        // new volume level
                        rows.Add(time, row = new GridRow {
                            Time = time, Volume = sumVol
                        });

                        // draw on chart
                        chartSeries.Append(DateTime.Today + time, (double)sumVol, (double)sumVol / 1000);

                        // draw on table
                        gridSeries.Add(row);
                    }
                    else
                    {
                        // update existing volume level
                        row.Volume += sumVol;

                        // update chart
                        chartSeries.Update(DateTime.Today + time, (double)row.Volume, (double)row.Volume / 1000);
                    }
                }

                chart.GuiAsync(() =>
                {
                    // update grid sorting
                    grid.RefreshSort();

                    // scale chart
                    chart.ZoomExtents();
                });
            }

            // notify the script stopped
            Stop();
        }
        /// <summary>
        /// Анализировать.
        /// </summary>
        protected override void OnAnalyze()
        {
            var chart = Chart;
            var grid  = Grid;

            var chartSeries = new XyzDataSeries <DateTime, double, double>();
            ThreadSafeObservableCollection <GridRow> gridSeries = null;

            chart.GuiSync(() =>
            {
                // очищаем данные с предыдущего запуска скрипта
                chart.RenderableSeries.Clear();
                grid.Columns.Clear();

                chart.RenderableSeries.Add(new FastBubbleRenderableSeries
                {
                    ResamplingMode = ResamplingMode.Auto,
                    BubbleColor    = Colors.Chocolate,
                    ZScaleFactor   = 0.1,
                    AutoZRange     = true,
                    DataSeries     = chartSeries
                });

                chart.XAxis = new DateTimeAxis {
                    GrowBy = new DoubleRange(0.0, 0.1)
                };
                chart.YAxis = new NumericAxis {
                    GrowBy = new DoubleRange(0.1, 0.1)
                };

                grid.AddTextColumn("Time", LocalizedStrings.Time).Width = 150;
                var volumeColumn   = grid.AddTextColumn("Volume", LocalizedStrings.Volume);
                volumeColumn.Width = 100;

                var gridSource   = new ObservableCollectionEx <GridRow>();
                grid.ItemsSource = gridSource;
                gridSeries       = new ThreadSafeObservableCollection <GridRow>(gridSource);

                grid.SetSort(volumeColumn, ListSortDirection.Descending);
            });

            // получаем хранилище свечек
            var storage = StorateRegistry.GetCandleStorage(typeof(TimeFrameCandle), Security, TimeFrame, format: StorageFormat);

            // получаем набор доступных дат за указанный период
            var dates = storage.GetDates(From, To).ToArray();

            var rows = new Dictionary <TimeSpan, GridRow>();

            foreach (var loadDate in dates)
            {
                // проверяем флаг остановки
                if (ProcessState != ProcessStates.Started)
                {
                    break;
                }

                // загружаем свечки
                var candles = storage.Load(loadDate);

                // группируем свечки по часовой отметке времени
                var groupedCandles = candles.GroupBy(c => c.OpenTime.TimeOfDay.Truncate(TimeSpan.FromHours(1)));

                foreach (var group in groupedCandles.OrderBy(g => g.Key))
                {
                    // проверяем флаг остановки
                    if (ProcessState != ProcessStates.Started)
                    {
                        break;
                    }

                    var time = group.Key;

                    // получаем суммарный объем в пределах часовой отметки
                    var sumVol = group.Sum(c => c.TotalVolume);

                    var row = rows.TryGetValue(time);
                    if (row == null)
                    {
                        // пришел новый уровень - добавляем новую запись
                        rows.Add(time, row = new GridRow {
                            Time = time, Volume = sumVol
                        });

                        // выводим на график
                        chartSeries.Append(DateTime.Today + time, (double)sumVol, (double)sumVol / 1000);

                        // выводит в таблицу
                        gridSeries.Add(row);
                    }
                    else
                    {
                        // увеличиваем суммарный объем
                        row.Volume += sumVol;

                        // обновляем график
                        chartSeries.Update(DateTime.Today + time, (double)row.Volume, (double)row.Volume / 1000);
                    }
                }

                chart.GuiAsync(() =>
                {
                    // обновление сортировки в таблице
                    grid.RefreshSort();

                    // автомасштабирование графика
                    chart.ZoomExtents();
                });
            }

            // оповещаем программу об окончании выполнения скрипта
            base.Stop();
        }
        public ErrorBarSeriesTernaryChartExampleView()
        {
            InitializeComponent();

            _random = new FasterRandom();

            cursorModButton.IsChecked  = false;
            tooltipModButton.IsChecked = false;

            // scatters series
            var scatterDataSeries1 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Residue"
            };
            var scatterDataSeries2 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Dolomite"
            };
            var scatterDataSeries3 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Calcite"
            };


            // Residue series
            for (int i = 0; i < 25; i++)
            {
                var x = _random.Next(0, 40);
                var z = _random.Next(40, 60);
                var y = 100 - (x + z);
                scatterDataSeries1.Append(x, y, z);
            }

            // Dolomite series
            for (int i = 0; i < 25; i++)
            {
                var x = _random.Next(0, 40);
                var z = _random.Next(10, 30);
                var y = 100 - (x + z);
                scatterDataSeries2.Append(x, y, z);
            }

            // Calcite series
            for (int i = 0; i < 25; i++)
            {
                var z = _random.Next(70, 90);
                var x = _random.Next(0, 100 - z);
                var y = 100 - (x + z);
                scatterDataSeries3.Append(x, y, z);
            }

            scatterSeries1.DataSeries = scatterDataSeries1;
            scatterSeries2.DataSeries = scatterDataSeries2;
            scatterSeries3.DataSeries = scatterDataSeries3;

            // errorbars series
            var errorBarDataSeries1 = (XyzDataSeries <double, double, double>)scatterDataSeries1.Clone();
            var errorBarDataSeries2 = (XyzDataSeries <double, double, double>)scatterDataSeries2.Clone();
            var errorBarDataSeries3 = (XyzDataSeries <double, double, double>)scatterDataSeries3.Clone();

            errorBarDataSeries1.SeriesName = "ResidueError";
            errorBarDataSeries2.SeriesName = "DolomiteError";
            errorBarDataSeries3.SeriesName = "CalciteError";

            // EllipseError series
            errorBarsSeries1.DataSeries = errorBarDataSeries1;

            // TriangleError series
            errorBarsSeries2.DataSeries = errorBarDataSeries2;

            // SquareError series
            errorBarsSeries3.DataSeries = errorBarDataSeries3;
        }
        public PolygonSeriesTernaryChartExampleView()
        {
            InitializeComponent();

            cursorModButton.IsChecked  = false;
            tooltipModButton.IsChecked = false;

            // Filled areas
            var polygonDataSeries1 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Clay"
            };
            var polygonDataSeries2 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Sandy clay"
            };
            var polygonDataSeries3 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Silty clay loam"
            };
            var polygonDataSeries4 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Sandy loam"
            };
            var polygonDataSeries5 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Loam"
            };
            var polygonDataSeries6 = new XyzDataSeries <double> {
                AcceptsUnsortedData = true, SeriesName = "Silt loam"
            };

            // Сlay series
            polygonDataSeries1.Append(0, 100, 0);
            polygonDataSeries1.Append(40, 60, 0);
            polygonDataSeries1.Append(40, 50, 10);
            polygonDataSeries1.Append(20, 50, 30);
            polygonDataSeries1.Append(0, 70, 30);

            // Sandy clay series
            polygonDataSeries2.Append(0, 70, 30);
            polygonDataSeries2.Append(20, 50, 30);
            polygonDataSeries2.Append(30, 50, 20);
            polygonDataSeries2.Append(30, 30, 40);
            polygonDataSeries2.Append(0, 30, 70);

            // Silty clay loam series
            polygonDataSeries3.Append(30, 50, 20);
            polygonDataSeries3.Append(40, 50, 10);
            polygonDataSeries3.Append(40, 60, 0);
            polygonDataSeries3.Append(70, 30, 0);
            polygonDataSeries3.Append(30, 30, 40);

            // Sandy loam series
            polygonDataSeries4.Append(30, 30, 40);
            polygonDataSeries4.Append(30, 0, 70);
            polygonDataSeries4.Append(0, 0, 100);
            polygonDataSeries4.Append(0, 30, 70);

            // Loam series
            polygonDataSeries5.Append(30, 30, 40);
            polygonDataSeries5.Append(50, 30, 20);
            polygonDataSeries5.Append(80, 0, 20);
            polygonDataSeries5.Append(30, 0, 70);

            // Silt loam series
            polygonDataSeries6.Append(50, 30, 20);
            polygonDataSeries6.Append(70, 30, 0);
            polygonDataSeries6.Append(100, 0, 0);
            polygonDataSeries6.Append(80, 0, 20);

            polygonSeries.DataSeries  = polygonDataSeries1;
            polygonSeries1.DataSeries = polygonDataSeries2;
            polygonSeries2.DataSeries = polygonDataSeries3;
            polygonSeries3.DataSeries = polygonDataSeries4;
            polygonSeries4.DataSeries = polygonDataSeries5;
            polygonSeries5.DataSeries = polygonDataSeries6;
        }
		/// <summary>
		/// To analyze.
		/// </summary>
		protected override void OnAnalyze()
		{
			var chart = Chart;
			var grid = Grid;

			var chartSeries = new XyzDataSeries<DateTime, double, double>();
			ThreadSafeObservableCollection<GridRow> gridSeries = null;

			chart.GuiSync(() =>
			{
				// очищаем данные с предыдущего запуска скрипта
				chart.RenderableSeries.Clear();
				grid.Columns.Clear();

				chart.RenderableSeries.Add(new FastBubbleRenderableSeries
				{
					ResamplingMode = ResamplingMode.Auto,
					BubbleColor = Colors.Chocolate,
					ZScaleFactor = 0.1,
					AutoZRange = true,
					DataSeries = chartSeries
				});

				chart.XAxis = new DateTimeAxis { GrowBy = new DoubleRange(0.0, 0.1) };
				chart.YAxis = new NumericAxis { GrowBy = new DoubleRange(0.1, 0.1) };

				grid.AddTextColumn("Time", LocalizedStrings.Time).Width = 150;
				var volumeColumn = grid.AddTextColumn("Volume", LocalizedStrings.Volume);
				volumeColumn.Width = 100;

				var gridSource = new ObservableCollectionEx<GridRow>();
				grid.ItemsSource = gridSource;
				gridSeries = new ThreadSafeObservableCollection<GridRow>(gridSource);

				grid.SetSort(volumeColumn, ListSortDirection.Descending);
			});

			// получаем хранилище свечек
			var storage = StorateRegistry.GetCandleStorage(typeof(TimeFrameCandle), Security, TimeFrame, format: StorageFormat);
			
			// получаем набор доступных дат за указанный период
			var dates = storage.GetDates(From, To).ToArray();

			var rows = new Dictionary<TimeSpan, GridRow>();

			foreach (var loadDate in dates)
			{
				// проверяем флаг остановки
				if (ProcessState != ProcessStates.Started)
					break;

				// загружаем свечки
				var candles = storage.Load(loadDate);

				// группируем свечки по часовой отметке времени
				var groupedCandles = candles.GroupBy(c => c.OpenTime.TimeOfDay.Truncate(TimeSpan.FromHours(1)));

				foreach (var group in groupedCandles.OrderBy(g => g.Key))
				{
					// проверяем флаг остановки
					if (ProcessState != ProcessStates.Started)
						break;

					var time = group.Key;

					// получаем суммарный объем в пределах часовой отметки
					var sumVol = group.Sum(c => c.TotalVolume);

					var row = rows.TryGetValue(time);
					if (row == null)
					{
						// пришел новый уровень - добавляем новую запись
						rows.Add(time, row = new GridRow { Time = time, Volume = sumVol });

						// выводим на график
						chartSeries.Append(DateTime.Today + time, (double)sumVol, (double)sumVol / 1000);

						// выводит в таблицу
						gridSeries.Add(row);
					}
					else
					{
						// увеличиваем суммарный объем
						row.Volume += sumVol;

						// обновляем график
						chartSeries.Update(DateTime.Today + time, (double)row.Volume, (double)row.Volume / 1000);
					}
				}
				
				chart.GuiAsync(() =>
				{
					// обновление сортировки в таблице
					grid.RefreshSort();

					// автомасштабирование графика
					chart.ZoomExtents();
				});
			}

			// оповещаем программу об окончании выполнения скрипта
			base.Stop();
		}
		/// <summary>
		/// To analyze.
		/// </summary>
		protected override void OnAnalyze()
		{
			var chart = Chart;
			var grid = Grid;

			var chartSeries = new XyzDataSeries<DateTime, double, double>();
			ThreadSafeObservableCollection<GridRow> gridSeries = null;

			chart.GuiSync(() =>
			{
				// clear prev values
				chart.RenderableSeries.Clear();
				grid.Columns.Clear();

				chart.RenderableSeries.Add(new FastBubbleRenderableSeries
				{
					ResamplingMode = ResamplingMode.Auto,
					BubbleColor = Colors.Chocolate,
					ZScaleFactor = 0.1,
					AutoZRange = true,
					DataSeries = chartSeries
				});

				chart.XAxis = new DateTimeAxis { GrowBy = new DoubleRange(0.0, 0.1) };
				chart.YAxis = new NumericAxis { GrowBy = new DoubleRange(0.1, 0.1) };

				grid.AddTextColumn("Time", LocalizedStrings.Time).Width = 150;
				var volumeColumn = grid.AddTextColumn("Volume", LocalizedStrings.Volume);
				volumeColumn.Width = 100;

				var gridSource = new ObservableCollectionEx<GridRow>();
				grid.ItemsSource = gridSource;
				gridSeries = new ThreadSafeObservableCollection<GridRow>(gridSource);

				grid.SetSort(volumeColumn, ListSortDirection.Descending);
			});

			// get candle storage
			var storage = StorateRegistry.GetCandleStorage(typeof(TimeFrameCandle), Security, TimeFrame, format: StorageFormat);
			
			// get available dates for the specified period
			var dates = storage.GetDates(From, To).ToArray();

			var rows = new Dictionary<TimeSpan, GridRow>();

			foreach (var loadDate in dates)
			{
				// check if stopped
				if (ProcessState != ProcessStates.Started)
					break;

				// load candles
				var candles = storage.Load(loadDate);

				// groupping candles by open time
				var groupedCandles = candles.GroupBy(c => c.OpenTime.TimeOfDay.Truncate(TimeSpan.FromHours(1)));

				foreach (var group in groupedCandles.OrderBy(g => g.Key))
				{
					// check if stopped
					if (ProcessState != ProcessStates.Started)
						break;

					var time = group.Key;

					// calc total volume for the specified time frame
					var sumVol = group.Sum(c => c.TotalVolume);

					var row = rows.TryGetValue(time);
					if (row == null)
					{
						// new volume level
						rows.Add(time, row = new GridRow { Time = time, Volume = sumVol });

						// draw on chart
						chartSeries.Append(DateTime.Today + time, (double)sumVol, (double)sumVol / 1000);

						// draw on table
						gridSeries.Add(row);
					}
					else
					{
						// update existing volume level
						row.Volume += sumVol;

						// update chart
						chartSeries.Update(DateTime.Today + time, (double)row.Volume, (double)row.Volume / 1000);
					}
				}
				
				chart.GuiAsync(() =>
				{
					// update grid sorting
					grid.RefreshSort();

					// scale chart
					chart.ZoomExtents();
				});
			}

			// notify the script stopped
			Stop();
		}