Table of Contents

Working with Charts in Strategies

In StockSharp, the Strategy class provides a convenient interface for visualizing trading activity on a chart. In this article, we'll look at how to access a chart from a strategy, create areas (ChartArea), add various elements (candles, indicators, trades), and render data.

Accessing the Chart

GetChart Method

To access the chart from a strategy, use the Strategy.GetChart() method:

protected override void OnStarted(DateTimeOffset time)
{
    base.OnStarted(time);
    
    // Obtaining the chart
    _chart = GetChart();
    
    // Checking chart availability
    if (_chart != null)
    {
        // Initializing the chart
        InitializeChart();
    }
    else
    {
        // Chart is unavailable, for example, when running in console mode
        LogInfo("Chart is unavailable. Visualization disabled.");
    }
}

The GetChart() method returns an IChart interface that provides access to chart functions. It's important to check the result for null, as the chart may be unavailable, for example, when running a strategy in console mode or cloud testing.

SetChart Method

In some cases, the chart may be set from outside. For this, use the Strategy.SetChart method:

// Setting the chart from an external source
public void ConfigureVisualization(IChart chart)
{
    SetChart(chart);
    
    if (chart != null)
    {
        InitializeChart();
    }
}

Creating Chart Areas

After obtaining access to the chart, you can create one or more areas to display various data. Use the CreateChartArea method:

private void InitializeChart()
{
    // Creating the main area for candles and indicators
    _mainArea = CreateChartArea();
    
    // Creating an additional area for volume
    _volumeArea = CreateChartArea();
    
    // Configuring areas and adding elements
    ConfigureChartElements();
}

You can also use the IChart.AddArea method directly:

private void InitializeChart()
{
    // Clear existing areas if necessary
    foreach (var area in _chart.Areas.ToArray())
        _chart.RemoveArea(area);
    
    // Create the main area for candles and indicators
    _mainArea = _chart.AddArea();
    
    // Create an additional area for volume
    _volumeArea = _chart.AddArea();
    
    // Configure areas and add elements
    ConfigureChartElements();
}

Adding Elements to the Chart

After creating chart areas, you can add various elements to display data. StockSharp supports different types of elements such as candles, indicators, trades, and orders.

Adding Candles

To display candles, use the AddCandles method of the chart area:

private void ConfigureChartElements()
{
    // Adding a candle element to the main area
    _candleElement = _mainArea.AddCandles();
    
    // Configuring candle display
    _candleElement.DrawStyle = ChartCandleDrawStyles.CandleStick; // Japanese candles
    _candleElement.AntiAliasing = true; // Smoothing
    _candleElement.UpFillColor = Color.Green; // Rising candle body color
    _candleElement.DownFillColor = Color.Red; // Falling candle body color
    _candleElement.UpBorderColor = Color.DarkGreen; // Rising candle border color
    _candleElement.DownBorderColor = Color.DarkRed; // Falling candle border color
    _candleElement.StrokeThickness = 1; // Line thickness
    _candleElement.ShowAxisMarker = true; // Show Y-axis marker
}

The IChartCandleElement interface provides many properties for configuring candle display:

  • DrawStyle - candle display style:

    • CandleStick - Japanese candles
    • Ohlc - bars
    • LineOpen/LineHigh/LineLow/LineClose - lines for respective prices
    • BoxVolume - volume boxes
    • ClusterProfile - cluster profile
    • Area - area
    • PnF - point and figure chart
  • Color settings:

    • UpFillColor/DownFillColor - rising/falling candle body color
    • UpBorderColor/DownBorderColor - rising/falling candle border color
    • LineColor - line color for line-type charts
    • AreaColor - area color for Area type
  • Other settings:

    • StrokeThickness - line thickness
    • AntiAliasing - smoothing
    • ShowAxisMarker - show Y-axis marker

Adding Indicators

To display indicators, use the DrawIndicator method:

// Creating indicators
_sma = new SimpleMovingAverage { Length = SmaLength };
_bollinger = new BollingerBands
{
    Length = BollingerLength,
    Deviation = BollingerDeviation
};

// Adding indicators to the strategy collection
Indicators.Add(_sma);
Indicators.Add(_bollinger);

// Visualizing indicators
_smaElement = DrawIndicator(_mainArea, _sma, Color.Blue);
_bollingerUpperElement = DrawIndicator(_mainArea, _bollinger, Color.Purple);
_bollingerLowerElement = DrawIndicator(_mainArea, _bollinger, Color.Purple);
_bollingerMiddleElement = DrawIndicator(_mainArea, _bollinger, Color.Gray);

The DrawIndicator method automatically creates an indicator element and adds it to the specified chart area. You can specify a color and additional color for display.

You can also add an indicator element directly through the chart area's AddIndicator method:

// Adding SMA directly through the chart area
var smaElement = _mainArea.AddIndicator(_sma);
smaElement.Color = Color.Blue;
smaElement.StrokeThickness = 2;
smaElement.DrawStyle = DrawStyles.Line;
smaElement.AntiAliasing = true;
smaElement.ShowAxisMarker = true;
smaElement.AutoAssignYAxis = true; // Automatically assign Y-axis

The IChartIndicatorElement interface provides the following properties for configuration:

  • Color - main indicator color
  • AdditionalColor - additional color (for indicators with two lines)
  • StrokeThickness - line thickness
  • AntiAliasing - smoothing
  • DrawStyle - drawing style (line, points, histogram, etc.)
  • ShowAxisMarker - show Y-axis marker
  • AutoAssignYAxis - automatically assign Y-axis

Adding Trades

To display trades, use the DrawOwnTrades method:

// Adding an element to display trades
_tradesElement = DrawOwnTrades(_mainArea);

// Configuring trade display
_tradesElement.BuyBrush = Color.Green;  // Buy color
_tradesElement.SellBrush = Color.Red;   // Sell color
_tradesElement.PointSize = 10;          // Point size

Adding Orders

To display orders, use the DrawOrders method:

// Adding an element to display orders
_ordersElement = DrawOrders(_mainArea);

// Configuring order display
_ordersElement.ActiveBrush = Color.Blue;     // Active orders color
_ordersElement.CanceledBrush = Color.Gray;   // Canceled orders color
_ordersElement.DoneBrush = Color.Green;      // Completed orders color
_ordersElement.ErrorColor = Color.Red;       // Error color
_ordersElement.PointSize = 8;                // Point size

The IChartOrderElement interface provides the following properties for configuration:

  • ActiveBrush - color of active orders
  • CanceledBrush - color of canceled orders
  • DoneBrush - color of completed orders
  • ErrorColor - error color
  • ErrorStrokeColor - error border color
  • Filter - order display filter

Drawing Data on the Chart

After configuring all chart elements, you can proceed to draw data. Different methods are used depending on the type of data.

Drawing Candles and Indicators

The most efficient way to draw data is to use the IChart.Draw method with an IChartDrawData object:

private void ProcessCandle(ICandleMessage candle)
{
    // Processing candle in indicators
    var smaValue = _sma.Process(candle);
    var bollingerValue = _bollinger.Process(candle);
    
    // If chart is unavailable, skip drawing
    if (_chart == null)
        return;
    
    // Create data for drawing
    var drawData = _chart.CreateData();
    
    // Group data by candle time
    var group = drawData.Group(candle.OpenTime);
    
    // Add candle
    group.Add(_candleElement, 
        candle.DataType, 
        candle.SecurityId, 
        candle.OpenPrice, 
        candle.HighPrice, 
        candle.LowPrice, 
        candle.ClosePrice, 
        candle.PriceLevels, 
        candle.State);
    
    // Add indicator values
    group.Add(_smaElement, smaValue);
    
    if (bollingerValue != null)
    {
        group.Add(_bollingerUpperElement, bollingerValue);
        group.Add(_bollingerMiddleElement, bollingerValue);
        group.Add(_bollingerLowerElement, bollingerValue);
    }
    
    // Draw data on the chart
    _chart.Draw(drawData);
}

The IChart.CreateData method creates an IChartDrawData object used to group and add data for different chart elements. Data grouping is done by timestamp using the Group method.

For adding data of different types, various overloads of the Add method of the IChartDrawDataItem object are used.

Simplified Drawing for a Single Element

If you need to draw data for only one element, you can use the simplified IChart.Draw method:

// Drawing a single candle
_chart.Draw(_candleElement, candle);

// Drawing indicator value
_chart.Draw(_smaElement, smaValue);

Drawing Trades and Orders

For drawing trades and orders, an automatic mechanism is usually used that is triggered when new trades are received or orders change. However, if manual drawing is required, you can use the following code:

// Drawing a trade
var tradeDrawData = _chart.CreateData();
var tradeGroup = tradeDrawData.Group(trade.Time);
tradeGroup.Add(_tradesElement, trade.Id, trade.StringId, trade.Side, trade.Price, trade.Volume);
_chart.Draw(tradeDrawData);

// Drawing an order
var orderDrawData = _chart.CreateData();
var orderGroup = orderDrawData.Group(order.Time);
orderGroup.Add(_ordersElement, order.Id, order.StringId, order.Side, order.Price, order.Volume);
_chart.Draw(orderDrawData);

Full Example of Chart Rendering in a Strategy

Below is a complete example of a strategy with chart setup and rendering:

public class SmaStrategy : Strategy
{
    private readonly StrategyParam<int> _smaLength;
    private readonly StrategyParam<int> _bollingerLength;
    private readonly StrategyParam<decimal> _bollingerDeviation;
    
    private SimpleMovingAverage _sma;
    private BollingerBands _bollinger;
    
    private IChart _chart;
    private IChartArea _mainArea;
    private IChartArea _volumeArea;
    
    private IChartCandleElement _candleElement;
    private IChartIndicatorElement _smaElement;
    private IChartIndicatorElement _bollingerUpperElement;
    private IChartIndicatorElement _bollingerMiddleElement;
    private IChartIndicatorElement _bollingerLowerElement;
    private IChartOrderElement _ordersElement;
    private IChartTradeElement _tradesElement;
    
    public SmaStrategy()
    {
        _smaLength = Param(nameof(SmaLength), 20);
        _bollingerLength = Param(nameof(BollingerLength), 20);
        _bollingerDeviation = Param(nameof(BollingerDeviation), 2m);
    }
    
    public int SmaLength
    {
        get => _smaLength.Value;
        set => _smaLength.Value = value;
    }
    
    public int BollingerLength
    {
        get => _bollingerLength.Value;
        set => _bollingerLength.Value = value;
    }
    
    public decimal BollingerDeviation
    {
        get => _bollingerDeviation.Value;
        set => _bollingerDeviation.Value = value;
    }
    
    protected override void OnStarted(DateTimeOffset time)
    {
        base.OnStarted(time);
        
        // Creating indicators
        _sma = new SimpleMovingAverage { Length = SmaLength };
        _bollinger = new BollingerBands
        {
            Length = BollingerLength,
            Deviation = BollingerDeviation
        };
        
        // Adding indicators to strategy collection
        Indicators.Add(_sma);
        Indicators.Add(_bollinger);
        
        // Getting the chart
        _chart = GetChart();
        
        // Initializing the chart if available
        if (_chart != null)
        {
            InitializeChart();
        }
        
        // Subscribing to candles
        var subscription = new Subscription(
            DataType.TimeFrame(TimeSpan.FromMinutes(5)),
            Security);
        
        subscription
            .WhenCandlesFinished(this)
            .Do(ProcessCandle)
            .Apply(this);
        
        Subscribe(subscription);
    }
    
    private void InitializeChart()
    {
        // Clear existing areas
        foreach (var area in _chart.Areas.ToArray())
            _chart.RemoveArea(area);
        
        // Create the main area for candles and indicators
        _mainArea = _chart.AddArea();
        
        // Create an additional area for volume
        _volumeArea = _chart.AddArea();
        
        // Configure chart elements
        ConfigureChartElements();
    }
    
    private void ConfigureChartElements()
    {
        // Adding an element for displaying candles
        _candleElement = _mainArea.AddCandles();
        _candleElement.DrawStyle = ChartCandleDrawStyles.CandleStick;
        _candleElement.AntiAliasing = true;
        _candleElement.UpFillColor = Color.Green;
        _candleElement.DownFillColor = Color.Red;
        _candleElement.UpBorderColor = Color.DarkGreen;
        _candleElement.DownBorderColor = Color.DarkRed;
        _candleElement.StrokeThickness = 1;
        _candleElement.ShowAxisMarker = true;
        
        // Adding elements for indicators
        _smaElement = _mainArea.AddIndicator(_sma);
        _smaElement.Color = Color.Blue;
        _smaElement.StrokeThickness = 2;
        
        _bollingerUpperElement = _mainArea.AddIndicator(_bollinger);
        _bollingerUpperElement.Color = Color.Purple;
        _bollingerUpperElement.StrokeThickness = 1;
        
        _bollingerMiddleElement = _mainArea.AddIndicator(_bollinger);
        _bollingerMiddleElement.Color = Color.Gray;
        _bollingerMiddleElement.StrokeThickness = 1;
        
        _bollingerLowerElement = _mainArea.AddIndicator(_bollinger);
        _bollingerLowerElement.Color = Color.Purple;
        _bollingerLowerElement.StrokeThickness = 1;
        
        // Adding elements for orders and trades
        _ordersElement = DrawOrders(_mainArea);
        _tradesElement = DrawOwnTrades(_mainArea);
    }
    
    private void ProcessCandle(ICandleMessage candle)
    {
        // Processing candle with indicators
        var smaValue = _sma.Process(candle);
        var bollingerValue = _bollinger.Process(candle);
        
        // If chart is unavailable, skip drawing
        if (_chart == null)
            return;
        
        // Drawing data on the chart
        var drawData = _chart.CreateData();
        var group = drawData.Group(candle.OpenTime);
        
        // Adding candle
        group.Add(_candleElement, 
            candle.DataType, 
            candle.SecurityId, 
            candle.OpenPrice, 
            candle.HighPrice, 
            candle.LowPrice, 
            candle.ClosePrice, 
            candle.PriceLevels, 
            candle.State);
        
        // Adding indicator values
        group.Add(_smaElement, smaValue);
        
        if (bollingerValue != null)
        {
            group.Add(_bollingerUpperElement, bollingerValue);
            group.Add(_bollingerMiddleElement, bollingerValue);
            group.Add(_bollingerLowerElement, bollingerValue);
        }
        
        // Drawing data on the chart
        _chart.Draw(drawData);
        
        // Trading logic
        if (!IsFormed)
            return;
            
        // ... implementation of trading logic ...
    }
}

Conclusion

Using charts in StockSharp strategies allows visualizing trading activity, which significantly simplifies the development, debugging, and monitoring of trading strategies. The Strategy class provides many methods for working with charts, allowing easy addition of various elements and rendering data.

When developing a strategy with a graphical interface, always consider that the chart may be unavailable, for example, when running in console mode or cloud testing. Therefore, it's important to check the result of the GetChart() method for null and provide an alternative scenario for the strategy to work without visualization.

See Also