The new high-performance candlestick series allows you to plot thousands of candlesticks and still support smooth user interaction. This is almost 9,000 candlestick points with zooming, panning and streaming enabled.
XAML + CODE +
<UserControl x:Class="Visiblox.Charts.Examples.RasterCandlestickSeries.RasterCandlestickSeriesExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:charts="clr-namespace:Visiblox.Charts;assembly=Visiblox.Charts"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<!--This is the style that we will add to the plot area to fill the background-->
<Style TargetType="Grid" x:Key="PlotAreaStyle">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
<GradientStop Color="#ffa8a9ad" Offset="0" />
<GradientStop Color="#ffd2d3d5" Offset="0.3" />
<GradientStop Color="White" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TextBlock" x:Key="IncreasingValue">
<Setter Property="Foreground" Value="#ff1f862b" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style TargetType="TextBlock" x:Key="DecreasingValue">
<Setter Property="Foreground" Value="#ffc11918" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style TargetType="Border" x:Key="AnnotationBorderStyle">
<Setter Property="BorderThickness" Value="0" />
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Border Background="White" CornerRadius="5">
<StackPanel Orientation="Vertical">
<!-- Define the chart, add zoom and a series with type CandleStickSeries -->
<!-- Ultimate Trial users should add 'ValidationKey="ENTER TRIAL LICENSE KEY HERE"' to each Chart declaration. -->
<charts:Chart Width="600" Height="350" Name="Chart" PlotAreaStyle="{StaticResource PlotAreaStyle}"
LegendVisibility="Collapsed" Title="ACME Share Price" HorizontalAlignment="Center" Margin="25,0,25,15">
<charts:Chart.Series>
<charts:RasterCandlestickSeries>
<charts:RasterCandlestickSeries.DefaultStyle>
<charts:CandlestickSeriesStyle FallingLineFill="#ffc11918" RisingLineFill="#ff1f862b"
FallingLineStroke="#ffc11918" RisingLineStroke="#ff1f862b"/>
</charts:RasterCandlestickSeries.DefaultStyle>
</charts:RasterCandlestickSeries>
</charts:Chart.Series>
<!-- Add zooming to the charts -->
<charts:Chart.Behaviour>
<charts:BehaviourManager AllowMultipleEnabled="True">
<charts:ZoomBehaviour YZoomEnabled="False" BehaviourActivator="RightMouse" AnimationEnabled="False"/>
<charts:PanBehaviour YPanEnabled="False" BehaviourActivator="LeftMouse" AllowPanBeyondData="False"/>
<charts:TrackballBehaviour />
</charts:BehaviourManager>
</charts:Chart.Behaviour>
<charts:Chart.YAxis>
<charts:LinearAxis LabelFormatString="N2" ShowMinorTicks="False" ShowMajorGridlines="True" Width="50">
<charts:LinearAxis.Range>
<charts:DoubleRange />
</charts:LinearAxis.Range>
</charts:LinearAxis>
</charts:Chart.YAxis>
<charts:Chart.XAxis>
<charts:DateTimeAxis Background="LightGray" ShowMinorTicks="False" ShowMajorGridlines="False" LabelCollisionDetectionMode="Hide" Height="30"/>
</charts:Chart.XAxis>
</charts:Chart>
<StackPanel Orientation="Vertical">
<Border Background="#ffd2d3d5" Height="55" Width="210" CornerRadius="2" HorizontalAlignment="Center" VerticalAlignment="Top">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="15" />
<RowDefinition Height="15" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="Date: " FontWeight="Bold" FontSize="10" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="High: " FontWeight="Bold" FontSize="10" />
<TextBlock Grid.Column="2" Grid.Row="1" Text="Low: " FontWeight="Bold" FontSize="10" />
<TextBlock Grid.Column="0" Grid.Row="2" Text="Open: " FontWeight="Bold" FontSize="10" />
<TextBlock Grid.Column="2" Grid.Row="2" Text="Close: " FontWeight="Bold" FontSize="10" />
<TextBlock Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="0" Text="{Binding ElementName=Chart, Path=Behaviour.Behaviours[2].CurrentPoints[0].X, StringFormat=dd MMM yyy HH:mm:ss}" FontSize="10" />
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding ElementName=Chart, Path=Behaviour.Behaviours[2].CurrentPoints[0][High], StringFormat=N2}" FontSize="10" />
<TextBlock Grid.Column="3" Grid.Row="1" Text="{Binding ElementName=Chart, Path=Behaviour.Behaviours[2].CurrentPoints[0][Low], StringFormat=N2}" FontSize="10" />
<TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding ElementName=Chart, Path=Behaviour.Behaviours[2].CurrentPoints[0][Open], StringFormat=N2}" FontSize="10" />
<TextBlock Grid.Column="3" Grid.Row="2" Text="{Binding ElementName=Chart, Path=Behaviour.Behaviours[2].CurrentPoints[0][Close], StringFormat=N2}" FontSize="10" />
</Grid>
</Border>
<ToggleButton Content="Start Data Streaming" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked"
HorizontalAlignment="Center" Width="150" Background="#ffd2d3d5" Margin="0, 10, 0, 0"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</UserControl>
^ Back To Top
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Threading;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls.Primitives;
namespace Visiblox.Charts.Examples.RasterCandlestickSeries
{
public partial class RasterCandlestickSeriesExample : UserControl
{
private int MAX_POINTS = 30 * 60 * 6;
private Random _random = new Random(20120419);
private DateTime _startDate = DateTime.Today.AddHours(8);
DispatcherTimer _timer = new DispatcherTimer();
private DataSeries<DateTime, double> _dataSeries = new DataSeries<DateTime, double>();
private Style RisingAnnotationStyle { get { return Resources["IncreasingValue"] as Style; } }
private Style FallingAnnotationStyle { get { return Resources["DecreasingValue"] as Style; } }
private Style AnnotationBorderStyle { get { return Resources["AnnotationBorderStyle"] as Style; } }
public RasterCandlestickSeriesExample()
{
InitializeComponent();
// Set the data source of the candlestick series
GenerateData();
Chart.Series.First().DataSeries = _dataSeries;
UpdateYAxisRangeToVisibleData(DateTime.MinValue, DateTime.MaxValue);
AxisEventRelay relay = new AxisEventRelay(Chart.XAxis, AxisEventTypes.ActualRangeEffectiveLimitsChanged);
relay.AxisEvent += new AxisEventRelay.AxisEventHandler(relay_AxisEvent);
ZoomHelper.DisablePathLengthRestriction = true;
_timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
_timer.Tick += new EventHandler(timer_Tick);
}
/// <summary>
/// Generate 2 days worth of randomly generated hloc data at 20 second increments.
/// </summary>
public void GenerateData()
{
DataPoint<DateTime, double> dataPoint = null;
for (int x = 0; x < MAX_POINTS; x++)
{
dataPoint = AddNewDataPoint() as DataPoint<DateTime, double>;
}
InitialiseAnnotation(true, dataPoint);
}
private void InitialiseAnnotation(bool increasing, IDataPoint firstPoint)
{
HorizontalLineWithValueAnnotation annotation = new HorizontalLineWithValueAnnotation(firstPoint);
annotation.HideCollidingAxisLabels = true;
annotation.IsInteractionEnabled = false;
annotation.LabelTextStyle = increasing ? RisingAnnotationStyle : FallingAnnotationStyle;
annotation.LabelBorderStyle = AnnotationBorderStyle;
Chart.Annotations.Add(annotation);
}
private void UpdateAnnotation(IDataPoint point)
{
IComparable previousValue = (Chart.Annotations[0] as HorizontalLineWithValueAnnotation).YValue;
bool increasing = previousValue.CompareTo(point[CandlestickSeries.Low]) < 0;
Chart.Annotations.Clear();
InitialiseAnnotation(increasing, point);
}
private IDataPoint AddNewDataPoint()
{
DataPoint<DateTime, double> previousPoint = null;
DataPoint<DateTime, double> newPoint = null;
double open = 100;
if (_dataSeries != null)
{
int count = _dataSeries.Count;
if (count > 0)
{
previousPoint = _dataSeries[count - 1];
}
DateTime date = previousPoint != null ? ((DateTime)previousPoint.X).AddSeconds(1) : _startDate.AddSeconds(count * 1);
bool increasing = _random.NextDouble() > 0.5;
newPoint = CreateDataPoint(date, previousPoint != null ? (double)previousPoint[CandlestickSeries.Open] : open, increasing);
_dataSeries.Add(newPoint);
}
return newPoint;
}
private DataPoint<DateTime, double> CreateDataPoint(DateTime date, double open, bool increasing)
{
double closeChange = _random.NextDouble();
double openChange = _random.NextDouble();
open = increasing ? open + openChange : open - openChange;
double close = increasing ? open + closeChange : open - closeChange;
double high = Math.Max(open, close) + _random.NextDouble();
double low = Math.Min(open, close) - _random.NextDouble();
Dictionary<object, double> values = new Dictionary<object, double>();
values.Add(CandlestickSeries.High, high);
values.Add(CandlestickSeries.Low, low);
values.Add(CandlestickSeries.Open, open);
values.Add(CandlestickSeries.Close, close);
return new MultiValuedDataPoint<DateTime, double>(date, values);
}
private void UpdateYAxisRangeToVisibleData(DateTime minimumRange, DateTime maximumRange)
{
double minimum = Double.MaxValue;
double maximum = Double.MinValue;
foreach (DataPoint<DateTime, double> point in Chart.Series[0].DataSeries)
{
if (point.X < minimumRange || point.X > maximumRange)
continue;
minimum = Math.Min(minimum, (double)point[CandlestickSeries.Low]);
maximum = Math.Max(maximum, (double)point[CandlestickSeries.High]);
}
double range = maximum - minimum;
double margin = range * 0.1;
minimum = minimum - margin;
maximum = maximum + margin;
(Chart.YAxis.Range as DoubleRange).Minimum = minimum;
(Chart.YAxis.Range as DoubleRange).Maximum = maximum;
}
private void relay_AxisEvent(object sender, AxisEventRelayEventArgs e)
{
UpdateYAxisRangeToVisibleData((DateTime)Chart.XAxis.ActualRange.EffectiveMinimum, (DateTime)Chart.XAxis.ActualRange.EffectiveMaximum);
}
private void timer_Tick(object sender, EventArgs e)
{
DataPoint<DateTime, double> newPoint = AddNewDataPoint() as DataPoint<DateTime, double>;
if (_dataSeries.Count > MAX_POINTS)
{
_dataSeries.RemoveAt(0);
}
UpdateAnnotation(newPoint);
}
private void ToggleButton_Checked(object sender, RoutedEventArgs e)
{
(sender as ToggleButton).Content = "Stop Data Streaming";
_timer.Start();
}
private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
{
(sender as ToggleButton).Content = "Start Data Streaming";
_timer.Stop();
}
}
}
^ Back To Top

