Combinación de velas: historial + tiempo real
Para combinar velas históricas con datos en tiempo real, es necesario inicializar los almacenamientos correspondientes: almacenamiento para objetos de trading CsvEntityRegistry, almacenamiento para datos de mercado StorageRegistry y el registro de almacenamiento de instantáneas SnapshotRegistry.
El proyecto Samples/Candles/CombineHistoryRealtime muestra esta configuración en la práctica:
Configuración de almacenamientos y conector
public partial class MainWindow
{
private readonly Connector _connector;
private const string _connectorFile = "ConnectorFile.json";
// Ruta a datos históricos
private readonly string _pathHistory = Paths.HistoryDataPath;
private readonly IFileSystem _fileSystem = Paths.FileSystem;
private Subscription _subscription;
private ChartCandleElement _candleElement;
private readonly ChannelExecutor _executor;
public MainWindow()
{
InitializeComponent();
_executor = TimeSpan.FromSeconds(1).CreateExecutorAndRun(ex => ex.LogError());
// Inicializar almacenamientos
var entityRegistry = new CsvEntityRegistry(_fileSystem, _pathHistory, _executor);
var storageRegistry = new StorageRegistry
{
DefaultDrive = new LocalMarketDataDrive(_fileSystem, _pathHistory)
};
// Crear conector con almacenamientos configurados
_connector = new Connector(
entityRegistry.Securities,
entityRegistry.PositionStorage,
new InMemoryExchangeInfoProvider(),
storageRegistry,
new SnapshotRegistry(_fileSystem, "SnapshotRegistry"));
// Registrar proveedor de adaptadores de mensajes
ConfigManager.RegisterService<IMessageAdapterProvider>(
new InMemoryMessageAdapterProvider(_connector.Adapter.InnerAdapters));
// Cargar ajustes del conector si el archivo existe
if (_fileSystem.FileExists(_connectorFile))
{
_connector.Load(_connectorFile.Deserialize<SettingsStorage>(_fileSystem));
}
// Establecer tipo de datos de vela predeterminado (5 minutos)
CandleDataTypeEdit.DataType = TimeSpan.FromMinutes(5).TimeFrame();
}
}
Configuración de la conexión
// Método para configurar parámetros de conexión
private void Setting_Click(object sender, RoutedEventArgs e)
{
// Abrir ventana de configuración del conector
if (_connector.Configure(this))
{
// Guardar ajustes en archivo
_connector.Save().Serialize(_fileSystem, _connectorFile);
}
}
// Método para conectarse al sistema de trading
private void Connect_Click(object sender, RoutedEventArgs e)
{
// Establecer el conector como fuente de datos para seleccionar instrumentos
SecurityPicker.SecurityProvider = _connector;
// Suscribirse al evento de recepción de velas
_connector.CandleReceived += Connector_CandleReceived;
// Connect
_connector.Connect();
}
Procesamiento de velas y visualización en el gráfico
// Controlador del evento de recepción de velas
private void Connector_CandleReceived(Subscription subscription, ICandleMessage candle)
{
// Dibujar la vela en el gráfico
Chart.Draw(_candleElement, candle);
}
Creación de la suscripción a velas
// Método llamado al seleccionar un instrumento
private void SecurityPicker_SecuritySelected(Security security)
{
// Comprobar si se seleccionó un instrumento
if (security == null)
return;
// Cancelar la suscripción anterior si existe
if (_subscription != null)
_connector.UnSubscribe(_subscription);
// Crear nueva suscripción para el instrumento seleccionado
_subscription = new(CandleDataTypeEdit.DataType, security)
{
MarketData =
{
// Solicitar datos históricos de los últimos 720 días
From = DateTime.Today.AddDays(-720),
// Modo: cargar datos históricos y construir en tiempo real
BuildMode = MarketDataBuildModes.LoadAndBuild,
}
};
// Configurar gráfico
Chart.ClearAreas();
// Crear área del gráfico y elemento para mostrar velas
var area = new ChartArea();
_candleElement = new ChartCandleElement();
// Añadir área y elemento al gráfico
Chart.AddArea(area);
// Vincular elemento del gráfico con la suscripción para dibujo automático
Chart.AddElement(area, _candleElement, _subscription);
// Iniciar suscripción
_connector.Subscribe(_subscription);
}
Ejemplo completo de la clase MainWindow
namespace StockSharp.Samples.Candles.CombineHistoryRealtime;
using System;
using System.Windows;
using Ecng.Common;
using Ecng.Serialization;
using Ecng.Configuration;
using Ecng.ComponentModel;
using Ecng.Logging;
using Ecng.IO;
using StockSharp.Configuration;
using StockSharp.Algo;
using StockSharp.Algo.Storages;
using StockSharp.Algo.Storages.Csv;
using StockSharp.BusinessEntities;
using StockSharp.Xaml;
using StockSharp.Messages;
using StockSharp.Xaml.Charting;
using StockSharp.Charting;
/// <summary>
/// Lógica de interacción para MainWindow.xaml
/// </summary>
public partial class MainWindow
{
private readonly Connector _connector;
private const string _connectorFile = "ConnectorFile.json";
private readonly string _pathHistory = Paths.HistoryDataPath;
private readonly IFileSystem _fileSystem = Paths.FileSystem;
private Subscription _subscription;
private ChartCandleElement _candleElement;
private readonly ChannelExecutor _executor;
public MainWindow()
{
InitializeComponent();
_executor = TimeSpan.FromSeconds(1).CreateExecutorAndRun(ex => ex.LogError());
var entityRegistry = new CsvEntityRegistry(_fileSystem, _pathHistory, _executor);
var storageRegistry = new StorageRegistry
{
DefaultDrive = new LocalMarketDataDrive(_fileSystem, _pathHistory)
};
_connector = new Connector(
entityRegistry.Securities,
entityRegistry.PositionStorage,
new InMemoryExchangeInfoProvider(),
storageRegistry,
new SnapshotRegistry(_fileSystem, "SnapshotRegistry"));
// registro de todos los conectores
ConfigManager.RegisterService<IMessageAdapterProvider>(
new InMemoryMessageAdapterProvider(_connector.Adapter.InnerAdapters));
if (_fileSystem.FileExists(_connectorFile))
{
_connector.Load(_connectorFile.Deserialize<SettingsStorage>(_fileSystem));
}
CandleDataTypeEdit.DataType = TimeSpan.FromMinutes(5).TimeFrame();
}
protected override void OnClosed(EventArgs e)
{
AsyncHelper.Run(_executor.DisposeAsync);
base.OnClosed(e);
}
private void Setting_Click(object sender, RoutedEventArgs e)
{
if (_connector.Configure(this))
{
_connector.Save().Serialize(_fileSystem, _connectorFile);
}
}
private void Connect_Click(object sender, RoutedEventArgs e)
{
SecurityPicker.SecurityProvider = _connector;
_connector.CandleReceived += Connector_CandleReceived;
_connector.Connect();
}
private void Connector_CandleReceived(Subscription subscription, ICandleMessage candle)
{
Chart.Draw(_candleElement, candle);
}
private void SecurityPicker_SecuritySelected(Security security)
{
if (security == null) return;
if (_subscription != null) _connector.UnSubscribe(_subscription);
_subscription = new(CandleDataTypeEdit.DataType, security)
{
MarketData =
{
From = DateTime.Today.AddDays(-720),
BuildMode = MarketDataBuildModes.LoadAndBuild,
}
};
// -----------------Gráfico--------------------------------
Chart.ClearAreas();
var area = new ChartArea();
_candleElement = new ChartCandleElement();
Chart.AddArea(area);
Chart.AddElement(area, _candleElement, _subscription);
_connector.Subscribe(_subscription);
}
}
Características del ejemplo
Important
Todas las clases que trabajan con el sistema de archivos (CsvEntityRegistry, LocalMarketDataDrive, SnapshotRegistry) requieren una instancia de IFileSystem en el constructor. Use Paths.FileSystem para la implementación estándar. CsvEntityRegistry también requiere ChannelExecutor para sincronizar el acceso al disco. Los métodos de serialización (Serialize, Deserialize) también aceptan IFileSystem como parámetro.
Creación de almacenamientos:
- CsvEntityRegistry se utiliza para almacenar entidades y requiere
IFileSystemyChannelExecutor - StorageRegistry se configura con la ruta al almacenamiento
- SnapshotRegistry se crea para trabajar con instantáneas y requiere
IFileSystem
- CsvEntityRegistry se utiliza para almacenar entidades y requiere
Creación de la suscripción:
- Se utiliza la clase Subscription
- El parámetro From en MarketData especifica la fecha inicial para cargar el historial
- Se establece BuildMode = MarketDataBuildModes.LoadAndBuild para la combinación automática de historial y tiempo real
Visualización en el gráfico:
- Se utiliza el método Chart.AddElement para vincular el elemento del gráfico con la suscripción
- El gráfico se actualiza automáticamente cuando se reciben nuevas velas
Manejo de eventos:
- Suscripción al evento CandleReceived para procesar las velas recibidas
- Cancelación de la suscripción anterior cuando cambia el instrumento seleccionado
Capacidades ampliadas
Puede ampliar este ejemplo con las siguientes funciones:
Seguimiento de la transición al modo en tiempo real
// Suscripción al evento de transición al modo de tiempo real
_connector.SubscriptionOnline += OnSubscriptionOnline;
// Controlador de evento
private void OnSubscriptionOnline(Subscription subscription)
{
if (subscription == _subscription)
{
this.GuiAsync(() => StatusLabel.Content = "Modo en línea");
}
}
Configuración del período de carga del historial
// Establecer periodo de carga de historial
private void SetHistoryPeriod(int days)
{
if (_subscription != null)
{
_connector.UnSubscribe(_subscription);
_subscription.MarketData.From = DateTime.Today.AddDays(-days);
_connector.Subscribe(_subscription);
}
}
Procesamiento adicional de velas
// Procesamiento extendido de velas con salida de información
private void ExtendedCandleProcessing(Subscription subscription, ICandleMessage candle)
{
// Dibujar la vela en el gráfico
Chart.Draw(_candleElement, candle);
// Enviar información de la vela a los logs
this.GuiAsync(() =>
{
var status = subscription.State == SubscriptionStates.Online ? "Real-time" : "History";
LogControl.LogMessage($"{status}: {candle.OpenTime} - O:{candle.OpenPrice} H:{candle.HighPrice} L:{candle.LowPrice} C:{candle.ClosePrice}");
});
}