Trabalhar com Gráficos em Estratégias

No StockSharp, a classe Strategy fornece uma interface conveniente para visualizar a actividade de negociação num gráfico. Neste artigo, veremos como aceder a um gráfico a partir de uma estratégia, criar áreas (ChartArea), adicionar vários elementos (velas, indicadores, negócios) e renderizar dados.

Aceder ao Gráfico

Método GetChart

Para aceder ao gráfico a partir de uma estratégia, use o método Strategy.GetChart():

protected override void OnStarted2(DateTime time)
{
	base.OnStarted2(time);
	
	// Obtendo o gráfico
	_chart = GetChart();
	
	// Verificando disponibilidade do gráfico
	if (_chart != null)
	{
		// Inicializando o gráfico
		InitializeChart();
	}
	else
	{
		// O gráfico está indisponível, por exemplo, ao executar em modo console
		LogInfo("O gráfico não está disponível. Visualização desativada.");
	}
}

O método GetChart() devolve uma interface IChart que fornece acesso às funções do gráfico. É importante verificar se o resultado é null, pois o gráfico pode estar indisponível, por exemplo, ao executar uma estratégia em modo de consola ou em testes na cloud.

Método SetChart

Em alguns casos, o gráfico pode ser definido a partir do exterior. Para isso, use o método Strategy.SetChart:

// Definindo gráfico a partir de fonte externa
public void ConfigureVisualization(IChart chart)
{
	SetChart(chart);
	
	if (chart != null)
	{
		InitializeChart();
	}
}

Criar Áreas de Gráfico

Depois de obter acesso ao gráfico, pode criar uma ou mais áreas para apresentar vários dados. Use o método CreateChartArea:

private void InitializeChart()
{
	// Criando área principal para velas e indicadores
	_mainArea = CreateChartArea();
	
	// Criando área adicional para volume
	_volumeArea = CreateChartArea();
	
	// Configurando áreas e adicionando elementos
	ConfigureChartElements();
}

Também pode usar directamente o método IChart.AddArea:

private void InitializeChart()
{
	// Limpar áreas existentes se necessário
	foreach (var area in _chart.Areas.ToArray())
		_chart.RemoveArea(area);
	
	// Criar área principal para velas e indicadores
	_mainArea = _chart.AddArea();
	
	// Criar área adicional para volume
	_volumeArea = _chart.AddArea();
	
	// Configurar áreas e adicionar elementos
	ConfigureChartElements();
}

Adicionar Elementos ao Gráfico

Depois de criar áreas de gráfico, pode adicionar vários elementos para apresentar dados. O StockSharp suporta diferentes tipos de elementos, como velas, indicadores, negócios e ordens.

Adicionar Velas

Para apresentar velas, use o método AddCandles da área do gráfico:

private void ConfigureChartElements()
{
	// Adicionando elemento de vela à área principal
	_candleElement = _mainArea.AddCandles();
	
	// Configurando exibição de velas
	_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
}

A interface IChartCandleElement fornece muitas propriedades para configurar a apresentação das velas:

  • DrawStyle - estilo de apresentação das velas:

    • CandleStick - velas japonesas
    • Ohlc - barras
    • LineOpen/LineHigh/LineLow/LineClose - linhas para os respectivos preços
    • BoxVolume - caixas de volume
    • ClusterProfile - perfil de cluster
    • Area - área
    • PnF - gráfico de ponto e figura
  • Definições de cor:

    • UpFillColor/DownFillColor - cor do corpo da vela ascendente/descendente
    • UpBorderColor/DownBorderColor - cor da margem da vela ascendente/descendente
    • LineColor - cor da linha para gráficos do tipo linha
    • AreaColor - cor da área para o tipo Area
  • Outras definições:

    • StrokeThickness - espessura da linha
    • AntiAliasing - suavização
    • ShowAxisMarker - mostrar marcador do eixo Y

Adicionar Indicadores

Para apresentar indicadores, use o método DrawIndicator:

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

// Adicionando indicadores à coleção da estratégia
Indicators.Add(_sma);
Indicators.Add(_bollinger);

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

O método DrawIndicator cria automaticamente um elemento de indicador e adiciona-o à área de gráfico especificada. Pode especificar uma cor e uma cor adicional para apresentação.

Também pode adicionar um elemento de indicador directamente através do método AddIndicator da área do gráfico:

// Adicionando SMA diretamente pela área do gráfico
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; // Atribuir automaticamente o eixo Y

A interface IChartIndicatorElement fornece as seguintes propriedades para configuração:

  • Color - cor principal do indicador
  • AdditionalColor - cor adicional (para indicadores com duas linhas)
  • StrokeThickness - espessura da linha
  • AntiAliasing - suavização
  • DrawStyle - estilo de desenho (linha, pontos, histograma, etc.)
  • ShowAxisMarker - mostrar marcador do eixo Y
  • AutoAssignYAxis - atribuir automaticamente o eixo Y

Adicionar Negócios

Para apresentar negócios, use o método DrawOwnTrades:

// Adicionando elemento para exibir negociações
_tradesElement = DrawOwnTrades(_mainArea);

// Configurando exibição de negociações
_tradesElement.BuyBrush = Color.Green;  // Buy color
_tradesElement.SellBrush = Color.Red;   // Sell color
_tradesElement.PointSize = 10;          // Point size

Adicionar Ordens

Para apresentar ordens, use o método DrawOrders:

// Adicionando elemento para exibir ordens
_ordersElement = DrawOrders(_mainArea);

// Configurando exibição de ordens
_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

A interface IChartOrderElement fornece as seguintes propriedades para configuração:

  • ActiveBrush - cor das ordens activas
  • CanceledBrush - cor das ordens canceladas
  • DoneBrush - cor das ordens concluídas
  • ErrorColor - cor de erro
  • ErrorStrokeColor - cor da margem de erro
  • Filter - filtro de apresentação de ordens

Desenhar Dados no Gráfico

Depois de configurar todos os elementos do gráfico, pode prosseguir para desenhar os dados. São usados métodos diferentes consoante o tipo de dados.

Desenhar Velas e Indicadores

A forma mais eficiente de desenhar dados é usar o método IChart.Draw com um objecto IChartDrawData:

private void ProcessCandle(ICandleMessage candle)
{
	// Processando vela nos indicadores
	var smaValue = _sma.Process(candle);
	var bollingerValue = _bollinger.Process(candle);
	
	// Se o gráfico não estiver disponível, ignorar o desenho
	if (_chart == null)
		return;
	
	// Criar dados para desenho
	var drawData = _chart.CreateData();
	
	// Agrupar dados pelo horário da vela
	var group = drawData.Group(candle.OpenTime);
	
	// Adicionar candle
	group.Add(_candleElement, 
		candle.DataType, 
		candle.SecurityId, 
		candle.OpenPrice, 
		candle.HighPrice, 
		candle.LowPrice, 
		candle.ClosePrice, 
		candle.PriceLevels, 
		candle.State);
	
	// Adicionar valores dos indicadores
	group.Add(_smaElement, smaValue);
	
	if (bollingerValue != null)
	{
		group.Add(_bollingerUpperElement, bollingerValue);
		group.Add(_bollingerMiddleElement, bollingerValue);
		group.Add(_bollingerLowerElement, bollingerValue);
	}
	
	// Desenhar dados no gráfico
	_chart.Draw(drawData);
}

O método IChart.CreateData cria um objecto IChartDrawData usado para agrupar e adicionar dados para diferentes elementos do gráfico. O agrupamento de dados é feito por carimbo temporal usando o método Group.

Para adicionar dados de diferentes tipos, são usadas várias sobrecargas do método Add do objecto IChartDrawDataItem.

Desenhar Negócios e Ordens

Para desenhar negócios e ordens, normalmente é usado um mecanismo automático accionado quando são recebidos novos negócios ou quando as ordens mudam. No entanto, se for necessário desenho manual, pode usar o seguinte código:

// Desenhando uma negociação
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);

// Desenhando uma ordem
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);

Exemplo Completo de Renderização de Gráfico numa Estratégia

Abaixo está um exemplo completo de uma estratégia com configuração e renderização de gráfico:

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 OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		
		// Criar indicadores
		_sma = new SimpleMovingAverage { Length = SmaLength };
		_bollinger = new BollingerBands
		{
			Length = BollingerLength,
			Deviation = BollingerDeviation
		};
		
		// Adicionando indicadores à coleção da estratégia
		Indicators.Add(_sma);
		Indicators.Add(_bollinger);
		
		// Obtendo o gráfico
		_chart = GetChart();
		
		// Inicializando o gráfico se disponível
		if (_chart != null)
		{
			InitializeChart();
		}
		
		// Assinando velas
		var subscription = new Subscription(
			DataType.TimeFrame(TimeSpan.FromMinutes(5)),
			Security);
		
		subscription
			.WhenCandlesFinished(this)
			.Do(ProcessCandle)
			.Apply(this);
		
		Subscribe(subscription);
	}
	
	private void InitializeChart()
	{
		// Limpar áreas existentes
		foreach (var area in _chart.Areas.ToArray())
			_chart.RemoveArea(area);
		
		// Criar área principal para velas e indicadores
		_mainArea = _chart.AddArea();
		
		// Criar área adicional para volume
		_volumeArea = _chart.AddArea();
		
		// Configurar elementos do gráfico
		ConfigureChartElements();
	}
	
	private void ConfigureChartElements()
	{
		// Adicionando elemento para exibir velas
		_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;
		
		// Adicionando elementos para indicadores
		_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;
		
		// Adicionando elementos para ordens e negociações
		_ordersElement = DrawOrders(_mainArea);
		_tradesElement = DrawOwnTrades(_mainArea);
	}
	
	private void ProcessCandle(ICandleMessage candle)
	{
		// Processando vela com indicadores
		var smaValue = _sma.Process(candle);
		var bollingerValue = _bollinger.Process(candle);
		
		// Se o gráfico não estiver disponível, ignorar o desenho
		if (_chart == null)
			return;
		
		// Desenhando dados no gráfico
		var drawData = _chart.CreateData();
		var group = drawData.Group(candle.OpenTime);
		
		// Adicionando vela
		group.Add(_candleElement, 
			candle.DataType, 
			candle.SecurityId, 
			candle.OpenPrice, 
			candle.HighPrice, 
			candle.LowPrice, 
			candle.ClosePrice, 
			candle.PriceLevels, 
			candle.State);
		
		// Adicionando valores dos indicadores
		group.Add(_smaElement, smaValue);
		
		if (bollingerValue != null)
		{
			group.Add(_bollingerUpperElement, bollingerValue);
			group.Add(_bollingerMiddleElement, bollingerValue);
			group.Add(_bollingerLowerElement, bollingerValue);
		}
		
		// Desenhando dados no gráfico
		_chart.Draw(drawData);
		
		// Lógica de negociação
		if (!IsFormed)
			return;
			
		// ... implementação da lógica de negociação ...
	}
}

Conclusão

Usar gráficos em estratégias StockSharp permite visualizar a actividade de negociação, o que simplifica significativamente o desenvolvimento, a depuração e a monitorização de estratégias de negociação. A classe Strategy fornece muitos métodos para trabalhar com gráficos, permitindo adicionar facilmente vários elementos e renderizar dados.

Ao desenvolver uma estratégia com interface gráfica, tenha sempre em conta que o gráfico pode estar indisponível, por exemplo, ao executar em modo de consola ou em testes na cloud. Por isso, é importante verificar se o resultado do método GetChart() é null e fornecer um cenário alternativo para a estratégia funcionar sem visualização.

Ver Também