private void RaiseCandleSeriesStopped(CandleSeries series) { CandleSeriesStopped?.Invoke(series); }
private RefPair <DateTimeOffset, IDictionary <IChartElement, object> >[] ProcessHistoryCandles(ChartIndicatorElement element, CandleSeries series) { var candles = this.GetCandleManager().GetCandles <Candle>(series).Where(c => c.State == CandleStates.Finished).ToArray(); return(candles .Select(candle => new RefPair <DateTimeOffset, IDictionary <IChartElement, object> >(candle.OpenTime, new Dictionary <IChartElement, object> { { element, CreateIndicatorValue(element, candle) } })) .ToArray()); }
/// <summary> /// Остановить подписку получения свечек, ранее созданную через <see cref="SubscribeCandles(StockSharp.Algo.Candles.CandleSeries,System.DateTimeOffset,System.DateTimeOffset)"/>. /// </summary> /// <param name="series">Серия свечек.</param> public void UnSubscribeCandles(CandleSeries series) { }
/// <summary> /// подписаться на получение свечек /// </summary> private void Subscrable() { try { while (true) { Thread.Sleep(50); if (_neadToStopThread) { return; } if (ServerType == ServerType.None || string.IsNullOrWhiteSpace(NamePaper)) { continue; } List <IServer> servers = ServerMaster.GetServers(); if (servers == null) { if (ServerType != ServerType.None) { ServerMaster.SetNeedServer(ServerType); } continue; } try { _myServer = servers.Find(server => server.ServerType == ServerType); } catch { // ignore continue; } if (_myServer == null) { if (ServerType != ServerType.None) { ServerMaster.SetNeedServer(ServerType); } continue; } else { _myServer.NewBidAscIncomeEvent -= ConnectorBotNewBidAscIncomeEvent; _myServer.NewMyTradeEvent -= ConnectorBot_NewMyTradeEvent; _myServer.NewOrderIncomeEvent -= ConnectorBot_NewOrderIncomeEvent; _myServer.NewMarketDepthEvent -= ConnectorBot_NewMarketDepthEvent; _myServer.NewTradeEvent -= ConnectorBot_NewTradeEvent; _myServer.TimeServerChangeEvent -= myServer_TimeServerChangeEvent; _myServer.NeadToReconnectEvent -= _myServer_NeadToReconnectEvent; _myServer.NewBidAscIncomeEvent += ConnectorBotNewBidAscIncomeEvent; _myServer.NewMyTradeEvent += ConnectorBot_NewMyTradeEvent; _myServer.NewOrderIncomeEvent += ConnectorBot_NewOrderIncomeEvent; _myServer.NewMarketDepthEvent += ConnectorBot_NewMarketDepthEvent; _myServer.NewTradeEvent += ConnectorBot_NewTradeEvent; _myServer.TimeServerChangeEvent += myServer_TimeServerChangeEvent; _myServer.NeadToReconnectEvent += _myServer_NeadToReconnectEvent; if (_myServer.ServerType == ServerType.Tester) { ((TesterServer)_myServer).TestingEndEvent -= ConnectorReal_TestingEndEvent; ((TesterServer)_myServer).TestingEndEvent += ConnectorReal_TestingEndEvent; } } Thread.Sleep(50); ServerConnectStatus stat = _myServer.ServerStatus; if (stat != ServerConnectStatus.Connect) { continue; } lock (_subscrableLocker) { if (_mySeries == null) { while (_mySeries == null) { if (_neadToStopThread) { return; } Thread.Sleep(100); _mySeries = _myServer.StartThisSecurity(_namePaper, TimeFrameBuilder); } _mySeries.СandleUpdeteEvent += MySeries_СandleUpdeteEvent; _mySeries.СandleFinishedEvent += MySeries_СandleFinishedEvent; _subscrabler = null; } } _subscrabler = null; if (SecuritySubscribeEvent != null) { SecuritySubscribeEvent(Security); } return; } } catch (Exception error) { SendNewLogMessage(error.ToString(), LogMessageType.Error); } }
/// <summary> /// Начать выгрузку данных по инструменту. /// </summary> /// <param name="namePaper">имя бумаги которую будем запускать</param> /// <param name="timeFrameBuilder">объект несущий в себе данные о таймФрейме</param> /// <returns>В случае удачи возвращает CandleSeries /// в случае неудачи null</returns> public CandleSeries StartThisSecurity(string namePaper, TimeFrameBuilder timeFrameBuilder) { try { if (_lastStartServerTime.AddSeconds(15) > DateTime.Now) { return(null); } // дальше по одному lock (_lockerStarter) { if (namePaper == "") { return(null); } // надо запустить сервер если он ещё отключен if (ServerStatus != ServerConnectStatus.Connect) { //MessageBox.Show("Сервер не запущен. Скачивание данных прервано. Инструмент: " + namePaper); return(null); } if (_securities == null || _portfolios == null) { Thread.Sleep(5000); return(null); } if (_lastStartServerTime != DateTime.MinValue && _lastStartServerTime.AddSeconds(15) > DateTime.Now) { return(null); } Security security = null; for (int i = 0; _securities != null && i < _securities.Count; i++) { if (_securities[i].Name == namePaper) { security = _securities[i]; break; } } if (security == null) { return(null); } CandleSeries series = new CandleSeries(timeFrameBuilder, security); lock (_serverLocker) { AstsServer.ListenBidAsks(security); } Thread.Sleep(2000); _candleManager.StartSeries(series); SendLogMessage("Инструмент " + series.Security.Name + "ТаймФрейм" + series.TimeFrame + " успешно подключен на получение данных и прослушивание свечек", LogMessageType.System); return(series); } } catch (Exception error) { SendLogMessage(error.ToString(), LogMessageType.Error); return(null); } }
/// <summary> /// начать выкачивать данный иснтрументн /// </summary> /// <param name="namePaper"> название инструмента</param> /// <param name="timeFrameBuilder">объект несущий в себе данные о ТаймФрейме нужном для серии</param> /// <returns>в случае успешного запуска возвращает CandleSeries, объект генерирующий свечи</returns> public CandleSeries StartThisSecurity(string namePaper, TimeFrameBuilder timeFrameBuilder) { try { lock (_lockerStarter) { if (namePaper == "") { return(null); } if (Portfolios == null || Securities == null) { return(null); } if (_lastStartServerTime != DateTime.MinValue && _lastStartServerTime.AddSeconds(15) > DateTime.Now) { return(null); } if (ServerStatus != ServerConnectStatus.Connect) { return(null); } if (_candleManager == null) { return(null); } Security security = null; for (int i = 0; _securities != null && i < _securities.Count; i++) { if (_securities[i].Name == namePaper) { security = _securities[i]; break; } } if (security == null) { return(null); } CandleSeries series = new CandleSeries(timeFrameBuilder, security, StartProgram.IsOsTrader); ServerRealization.Subscrible(security); Thread.Sleep(300); _candleManager.StartSeries(series); SendLogMessage("Инструмент " + series.Security.Name + "ТаймФрейм" + series.TimeFrame + " успешно подключен на получение данных и прослушивание свечек", LogMessageType.System); if (_tickStorage != null) { _tickStorage.SetSecurityToSave(security); } return(series); } } catch (Exception error) { SendLogMessage(error.ToString(), LogMessageType.Error); return(null); } }
private void RaiseCandleSeriesError(CandleSeries series, SubscriptionResponseMessage reply) { CandleSeriesError?.Invoke(series, reply); }
private void OnNewCandles(CandleSeries series, IEnumerable <Candle> candles) { _candleBuffer.Add(series.Security, candles); }
private void OnChartPanelSubscribeCandleElement(ChartCandleElement element, CandleSeries candleSeries) { new SubscribeCandleElementCommand(element, candleSeries).Process(this); }
private void OnChartPanelSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { new SubscribeIndicatorElementCommand(element, candleSeries, indicator).Process(this); }
private void OnChartPanelSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries candleSeries, IIndicator indicator) { _bufferedChart.SetSource(element, candleSeries); _indicators.Add(element, indicator); AddElement(element, candleSeries); }
private void OnChartPanelSubscribeCandleElement(ChartCandleElement element, CandleSeries candleSeries) { AddElement(element, candleSeries); }
private void StartClick(object sender, RoutedEventArgs e) { // если были получены и инструмент, и портфель if (_strategy == null) { if (Portfolios.SelectedPortfolio == null) { MessageBox.Show(this, LocalizedStrings.Str3009); return; } // создаем скользящие средние, на 80 5-минуток и 10 5-минуток var longSma = new SimpleMovingAverage { Length = 80 }; var shortSma = new SimpleMovingAverage { Length = 10 }; // регистрируем наш тайм-фрейм var series = new CandleSeries(typeof(TimeFrameCandle), _lkoh, _timeFrame); // создаем торговую стратегию _strategy = new SmaStrategy(_candleManager, series, longSma, shortSma) { Volume = 1, Security = _lkoh, Portfolio = Portfolios.SelectedPortfolio, Connector = _trader, }; _logManager.Sources.Add(_strategy); //_strategy.Log += OnLog; _strategy.PropertyChanged += OnStrategyPropertyChanged; _candlesElem = new ChartCandleElement(); _area.Elements.Add(_candlesElem); _longMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Long, Color = Colors.OrangeRed }; _area.Elements.Add(_longMaElem); _shortMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Short, Color = Colors.RoyalBlue }; _area.Elements.Add(_shortMaElem); var marketTime = _trader.CurrentTime; // начинаем получать свечи за период в 5 дней _candleManager.Start(series, DateTime.Today - TimeSpan.FromDays(5), marketTime); _lastHistoryCandle = _timeFrame.GetCandleBounds(marketTime).Min; Report.IsEnabled = true; } if (_strategy.ProcessState == ProcessStates.Stopped) { // запускаем процесс получения стакана, необходимый для работы алгоритма котирования _trader.RegisterMarketDepth(_strategy.Security); _strategy.Start(); Start.Content = LocalizedStrings.Str242; } else { _trader.UnRegisterMarketDepth(_strategy.Security); _strategy.Stop(); Start.Content = LocalizedStrings.Str2421; } }
/// <summary> /// To notify the container about the start of the data getting for the series. /// </summary> /// <param name="series">Candles series.</param> /// <param name="from">The initial date from which data will be get.</param> /// <param name="to">The final date by which data will be get.</param> public void Start(CandleSeries series, DateTimeOffset from, DateTimeOffset to) { if (series == null) throw new ArgumentNullException("series"); var info = _info.SafeAdd(series, key => new SeriesInfo(this)); info.Reset(from); }
IEnumerable <Range <DateTimeOffset> > IExternalCandleSource.GetSupportedRanges(CandleSeries series) { if (!UseExternalCandleSource) { yield break; } var securityId = series.Security.ToSecurityId(); var messageType = series.CandleType.ToCandleMessageType(); var dataType = messageType.ToCandleMarketDataType(); if (_historySourceSubscriptions.ContainsKey(Tuple.Create(securityId, dataType, series.Arg))) { yield return(new Range <DateTimeOffset>(DateTimeOffset.MinValue, DateTimeOffset.MaxValue)); yield break; } var types = HistoryMessageAdapter.Drive.GetAvailableDataTypes(securityId, HistoryMessageAdapter.StorageFormat); foreach (var tuple in types) { if (tuple.MessageType != messageType || !tuple.Arg.Equals(series.Arg)) { continue; } var dates = HistoryMessageAdapter.StorageRegistry.GetCandleMessageStorage(tuple.MessageType, series.Security, series.Arg, HistoryMessageAdapter.Drive, HistoryMessageAdapter.StorageFormat).Dates.ToArray(); if (dates.Any()) { yield return(new Range <DateTimeOffset>(dates.First().ApplyTimeZone(TimeZoneInfo.Utc), dates.Last().ApplyTimeZone(TimeZoneInfo.Utc))); } break; } }
/// <summary> /// To get all data by the candle. /// </summary> /// <param name="series">Candles series.</param> /// <param name="candle">The candle for which you need to find data.</param> /// <returns>Found data.</returns> public IEnumerable<ICandleBuilderSourceValue> GetValues(CandleSeries series, Candle candle) { return GetInfo(series).GetValues(candle); }
IEnumerable <Range <DateTimeOffset> > IExternalCandleSource.GetSupportedRanges(CandleSeries series) { if (series.CandleType != typeof(TimeFrameCandle) || !(series.Arg is TimeSpan)) { yield break; } var tf = (TimeSpan)series.Arg; if (OpenECryMessageAdapter.TimeFrames.Contains(tf)) { yield return(new Range <DateTimeOffset>(DateTimeOffset.MinValue, CurrentTime)); } }
/// <summary> /// Начать выгрузку данных по инструменту. /// </summary> /// <param name="namePaper">имя бумаги которую будем запускать</param> /// <param name="timeFrameBuilder">объект несущий </param> /// <returns>В случае удачи возвращает CandleSeries /// в случае неудачи null</returns> public CandleSeries StartThisSecurity(string namePaper, TimeFrameBuilder timeFrameBuilder) { try { if (_lastStartServerTime.AddSeconds(15) > DateTime.Now) { return(null); } lock (_lockerStarter) { if (namePaper == "") { return(null); } // надо запустить сервер если он ещё отключен if (ServerStatus != ServerConnectStatus.Connect) { //MessageBox.Show("Сервер не запущен. Скачивание данных прервано. Инструмент: " + namePaper); return(null); } if (_securities == null || _portfolios == null) { Thread.Sleep(5000); return(null); } if (_lastStartServerTime != DateTime.MinValue && _lastStartServerTime.AddSeconds(15) > DateTime.Now) { return(null); } Security security = null; for (int i = 0; _securities != null && i < _securities.Count; i++) { if (_securities[i].Name == namePaper) { security = _securities[i]; break; } } if (security == null) { return(null); } if (_connectedContracts == null) { _connectedContracts = new List <string>(); } if (_connectedContracts.Find(s => s == security.Name) == null) { _connectedContracts.Add(security.Name); } _tickStorage.SetSecurityToSave(security); // 2 создаём серию свечек CandleSeries series = new CandleSeries(timeFrameBuilder, security); if (NeadToGetCandles(timeFrameBuilder.TimeFrame)) { // подгружаем в серию свечки, если коннектор это позволяет short count = 500; string price = "MBA"; string instrument = security.Name; string granularity = GetTimeFrameInOandaFormat(timeFrameBuilder.TimeFrame).ToString(); var parameters = new Dictionary <string, string>(); parameters.Add("price", price); parameters.Add("granularity", granularity); parameters.Add("count", count.ToString()); Task <List <CandlestickPlus> > result = Rest20.GetCandlesAsync(instrument, parameters); while (!result.IsCanceled && !result.IsCompleted && !result.IsFaulted) { Thread.Sleep(10); } List <CandlestickPlus> candleOanda = result.Result; List <Candle> candlesOsEngine = new List <Candle>(); for (int i = 0; i < candleOanda.Count; i++) { Candle newCandle = new Candle(); newCandle.Open = Convert.ToDecimal(candleOanda[i].bid.o); newCandle.High = Convert.ToDecimal(candleOanda[i].bid.h); newCandle.Low = Convert.ToDecimal(candleOanda[i].bid.l); newCandle.Close = Convert.ToDecimal(candleOanda[i].bid.c); newCandle.TimeStart = DateTime.Parse(candleOanda[i].time); newCandle.State = CandleStates.Finished; newCandle.Volume = candleOanda[i].volume; candlesOsEngine.Add(newCandle); } series.CandlesAll = candlesOsEngine; } _candleManager.StartSeries(series); SendLogMessage("Инструмент " + series.Security.Name + "ТаймФрейм " + series.TimeFrame + " успешно подключен на получение данных и прослушивание свечек", LogMessageType.System); return(series); } } catch (Exception error) { SendLogMessage(error.ToString(), LogMessageType.Error); return(null); } }
private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator) { _dataThreadActions.Add(() => { var oldReset = Chart.DisableIndicatorReset; try { Chart.DisableIndicatorReset = true; indicator.Reset(); } finally { Chart.DisableIndicatorReset = oldReset; } var chartData = new ChartDrawData(); foreach (var candle in _allCandles.CachedValues) { chartData.Group(candle.OpenTime).Add(element, indicator.Process(candle)); } Chart.Reset(new[] { element }); Chart.Draw(chartData); _indicators[element] = indicator; }); }
/// <summary> /// изменились серии свечек /// </summary> private void _candleManager_CandleUpdateEvent(CandleSeries series) { _candleSeriesToSend.Enqueue(series); }
private void StartBtnClick(object sender, RoutedEventArgs e) { if (HistoryPath.Text.IsEmpty() || !Directory.Exists(HistoryPath.Text)) { MessageBox.Show(this, LocalizedStrings.Str3014); return; } if (Math.Abs(TestingProcess.Value - 0) > double.Epsilon) { MessageBox.Show(this, LocalizedStrings.Str3015); return; } var logManager = new LogManager(); var fileLogListener = new FileLogListener("sample.log"); logManager.Listeners.Add(fileLogListener); // SMA periods var periods = new[] { new Tuple <int, int, Color>(80, 10, Colors.DarkGreen), new Tuple <int, int, Color>(70, 8, Colors.Red), new Tuple <int, int, Color>(60, 6, Colors.DarkBlue) }; // storage to historical data var storageRegistry = new StorageRegistry { // set historical path DefaultDrive = new LocalMarketDataDrive(HistoryPath.Text) }; var timeFrame = TimeSpan.FromMinutes(5); // create test security var security = new Security { Id = "RIZ2@FORTS", // sec id has the same name as folder with historical data Code = "RIZ2", Name = "RTS-12.12", Board = ExchangeBoard.Forts, }; var startTime = new DateTime(2012, 10, 1); var stopTime = new DateTime(2012, 10, 31); var level1Info = new Level1ChangeMessage { SecurityId = security.ToSecurityId(), ServerTime = startTime, } .TryAdd(Level1Fields.PriceStep, 10m) .TryAdd(Level1Fields.StepPrice, 6m) .TryAdd(Level1Fields.MinPrice, 10m) .TryAdd(Level1Fields.MaxPrice, 1000000m) .TryAdd(Level1Fields.MarginBuy, 10000m) .TryAdd(Level1Fields.MarginSell, 10000m); // test portfolio var portfolio = new Portfolio { Name = "test account", BeginValue = 1000000, }; // create backtesting connector var batchEmulation = new BatchEmulation(new[] { security }, new[] { portfolio }, storageRegistry) { EmulationSettings = { MarketTimeChangedInterval = timeFrame, StartTime = startTime, StopTime = stopTime, // count of parallel testing strategies BatchSize = periods.Length, } }; // handle historical time for update ProgressBar batchEmulation.ProgressChanged += (curr, total) => this.GuiAsync(() => TestingProcess.Value = total); batchEmulation.StateChanged += (oldState, newState) => { if (batchEmulation.State != EmulationStates.Stopped) { return; } this.GuiAsync(() => { if (batchEmulation.IsFinished) { TestingProcess.Value = TestingProcess.Maximum; MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime)); } else { MessageBox.Show(this, LocalizedStrings.cancelled); } }); }; // get emulation connector var connector = batchEmulation.EmulationConnector; logManager.Sources.Add(connector); connector.NewSecurities += securities => { if (securities.All(s => s != security)) { return; } // fill level1 values connector.SendInMessage(level1Info); connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security)) { // order book freq refresh is 1 sec Interval = TimeSpan.FromSeconds(1), }); }; TestingProcess.Maximum = 100; TestingProcess.Value = 0; _startEmulationTime = DateTime.Now; var strategies = periods .Select(period => { var candleManager = new CandleManager(connector); var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame); // create strategy based SMA var strategy = new SmaStrategy(candleManager, series, new SimpleMovingAverage { Length = period.Item1 }, new SimpleMovingAverage { Length = period.Item2 }) { Volume = 1, Security = security, Portfolio = portfolio, Connector = connector, // by default interval is 1 min, // it is excessively for time range with several months UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>() }; strategy.SetCandleManager(candleManager); var curveItems = Curve.CreateCurve(LocalizedStrings.Str3026Params.Put(period.Item1, period.Item2), period.Item3); strategy.PnLChanged += () => { var data = new EquityData { Time = strategy.CurrentTime, Value = strategy.PnL, }; this.GuiAsync(() => curveItems.Add(data)); }; Stat.AddStrategies(new[] { strategy }); return(strategy); }) .ToEx(periods.Length); // start emulation batchEmulation.Start(strategies); }
/// <summary> /// Подписаться на получение свечек. /// </summary> /// <param name="series">Серия свечек.</param> /// <param name="from">Начальная дата, с которой необходимо получать данные.</param> /// <param name="to">Конечная дата, до которой необходимо получать данные.</param> public void SubscribeCandles(CandleSeries series, DateTimeOffset from, DateTimeOffset to) { SubscribeCandles(series, from, to, TransactionIdGenerator.GetNextId()); }
private void StartBtnClick(object sender, RoutedEventArgs e) { // if process was already started, will stop it now if (_connector != null && _connector.State != EmulationStates.Stopped) { _strategy.Stop(); _connector.Disconnect(); _logManager.Sources.Clear(); _connector = null; return; } // create test security var security = new Security { Id = "AAPL@NASDAQ", Code = "AAPL", Name = "AAPL Inc", Board = ExchangeBoard.Nasdaq, }; var startTime = new DateTime(2009, 6, 1); var stopTime = new DateTime(2009, 9, 1); var level1Info = new Level1ChangeMessage { SecurityId = security.ToSecurityId(), ServerTime = startTime, } .TryAdd(Level1Fields.PriceStep, 10m) .TryAdd(Level1Fields.StepPrice, 6m) .TryAdd(Level1Fields.MinPrice, 10m) .TryAdd(Level1Fields.MaxPrice, 1000000m) .TryAdd(Level1Fields.MarginBuy, 10000m) .TryAdd(Level1Fields.MarginSell, 10000m); // test portfolio var portfolio = new Portfolio { Name = "test account", BeginValue = 1000000, }; var timeFrame = TimeSpan.FromMinutes(5); // create backtesting connector _connector = new HistoryEmulationConnector( new[] { security }, new[] { portfolio }) { HistoryMessageAdapter = { // set history range StartDate = startTime, StopDate = stopTime, }, // set market time freq as time frame MarketTimeChangedInterval = timeFrame, }; _logManager.Sources.Add(_connector); var candleManager = new CandleManager(_connector); var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame); // create strategy based on 80 5-min и 10 5-min _strategy = new SmaStrategy(candleManager, series, new SimpleMovingAverage { Length = 80 }, new SimpleMovingAverage { Length = 10 }) { Volume = 1, Security = security, Portfolio = portfolio, Connector = _connector, }; _connector.NewSecurities += securities => { if (securities.All(s => s != security)) { return; } // fill level1 values _connector.SendInMessage(level1Info); _connector.RegisterTrades(new RandomWalkTradeGenerator(_connector.GetSecurityId(security))); _connector.RegisterMarketDepth(new TrendMarketDepthGenerator(_connector.GetSecurityId(security)) { GenerateDepthOnEachTrade = false }); // start strategy before emulation started _strategy.Start(); candleManager.Start(series); // start historical data loading when connection established successfully and all data subscribed _connector.Start(); }; // fill parameters panel ParameterGrid.Parameters.Clear(); ParameterGrid.Parameters.AddRange(_strategy.StatisticManager.Parameters); _strategy.PnLChanged += () => { var data = new EquityData { Time = _strategy.CurrentTime, Value = _strategy.PnL, }; this.GuiAsync(() => _curveItems.Add(data)); }; _logManager.Sources.Add(_strategy); // ProgressBar refresh step var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>(); var nextTime = startTime + progressStep; TestingProcess.Maximum = 100; TestingProcess.Value = 0; // handle historical time for update ProgressBar _connector.MarketTimeChanged += diff => { if (_connector.CurrentTime < nextTime && _connector.CurrentTime < stopTime) { return; } var steps = (_connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1; nextTime = startTime + (steps * progressStep.Ticks).To <TimeSpan>(); this.GuiAsync(() => TestingProcess.Value = steps); }; _connector.StateChanged += () => { if (_connector.State == EmulationStates.Stopped) { this.GuiAsync(() => { Report.IsEnabled = true; if (_connector.IsFinished) { TestingProcess.Value = TestingProcess.Maximum; MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime)); } else { MessageBox.Show(this, LocalizedStrings.cancelled); } }); } }; _curveItems.Clear(); Report.IsEnabled = false; _startEmulationTime = DateTime.Now; // raise NewSecurities and NewPortfolio for full fill strategy properties _connector.Connect(); }
/// <summary> /// Получить временные диапазоны, для которых у данного источника для передаваемой серии свечек есть данные. /// </summary> /// <param name="series">Серия свечек.</param> /// <returns>Временные диапазоны.</returns> IEnumerable <Range <DateTimeOffset> > IExternalCandleSource.GetSupportedRanges(CandleSeries series) { if (series.CandleType == typeof(TimeFrameCandle) && series.Arg is TimeSpan && SmartComTimeFrames.CanConvert((TimeSpan)series.Arg)) { yield return(new Range <DateTimeOffset>(DateTimeOffset.MinValue, CurrentTime)); } }
private void StartBtnClick(object sender, RoutedEventArgs e) { if (_connectors.Count > 0) { foreach (var connector in _connectors) { connector.Start(); } return; } if (HistoryPath.Folder.IsEmpty() || !Directory.Exists(HistoryPath.Folder)) { MessageBox.Show(this, LocalizedStrings.Str3014); return; } if (_connectors.Any(t => t.State != EmulationStates.Stopped)) { MessageBox.Show(this, LocalizedStrings.Str3015); return; } var secGen = new SecurityIdGenerator(); var id = secGen.Split(SecId.Text); //if (secIdParts.Length != 2) //{ // MessageBox.Show(this, LocalizedStrings.Str3016); // return; //} var timeFrame = TimeSpan.FromMinutes(TimeFrame.SelectedIndex == 0 ? 1 : 5); var secCode = id.SecurityCode; var board = ExchangeBoard.GetOrCreateBoard(id.BoardCode); // create test security var security = new Security { Id = SecId.Text, // sec id has the same name as folder with historical data Code = secCode, Board = board, }; if (FinamCandlesCheckBox.IsChecked == true) { _finamHistorySource.Refresh(new FinamSecurityStorage(security), security, s => {}, () => false); } // create backtesting modes var settings = new[] { Tuple.Create( TicksCheckBox, TicksProgress, TicksParameterGrid, // ticks new EmulationInfo { UseTicks = true, CurveColor = Colors.DarkGreen, StrategyName = LocalizedStrings.Ticks }, TicksChart, TicksEquity, TicksPosition), Tuple.Create( TicksAndDepthsCheckBox, TicksAndDepthsProgress, TicksAndDepthsParameterGrid, // ticks + order book new EmulationInfo { UseTicks = true, UseMarketDepth = true, CurveColor = Colors.Red, StrategyName = LocalizedStrings.XamlStr757 }, TicksAndDepthsChart, TicksAndDepthsEquity, TicksAndDepthsPosition), Tuple.Create( DepthsCheckBox, DepthsProgress, DepthsParameterGrid, // order book new EmulationInfo { UseMarketDepth = true, CurveColor = Colors.OrangeRed, StrategyName = LocalizedStrings.MarketDepths }, DepthsChart, DepthsEquity, DepthsPosition), Tuple.Create( CandlesCheckBox, CandlesProgress, CandlesParameterGrid, // candles new EmulationInfo { UseCandleTimeFrame = timeFrame, CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.Candles }, CandlesChart, CandlesEquity, CandlesPosition), Tuple.Create( CandlesAndDepthsCheckBox, CandlesAndDepthsProgress, CandlesAndDepthsParameterGrid, // candles + orderbook new EmulationInfo { UseMarketDepth = true, UseCandleTimeFrame = timeFrame, CurveColor = Colors.Cyan, StrategyName = LocalizedStrings.XamlStr635 }, CandlesAndDepthsChart, CandlesAndDepthsEquity, CandlesAndDepthsPosition), Tuple.Create( OrderLogCheckBox, OrderLogProgress, OrderLogParameterGrid, // order log new EmulationInfo { UseOrderLog = true, CurveColor = Colors.CornflowerBlue, StrategyName = LocalizedStrings.OrderLog }, OrderLogChart, OrderLogEquity, OrderLogPosition), Tuple.Create( Level1CheckBox, Level1Progress, Level1ParameterGrid, // order log new EmulationInfo { UseLevel1 = true, CurveColor = Colors.Aquamarine, StrategyName = LocalizedStrings.Level1 }, Level1Chart, Level1Equity, Level1Position), Tuple.Create( FinamCandlesCheckBox, FinamCandlesProgress, FinamCandlesParameterGrid, // candles new EmulationInfo { UseCandleTimeFrame = timeFrame, HistorySource = d => _finamHistorySource.GetCandles(security, timeFrame, d.Date, d.Date), CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.FinamCandles }, FinamCandlesChart, FinamCandlesEquity, FinamCandlesPosition), Tuple.Create( YahooCandlesCheckBox, YahooCandlesProgress, YahooCandlesParameterGrid, // candles new EmulationInfo { UseCandleTimeFrame = timeFrame, HistorySource = d => new YahooHistorySource().GetCandles(security, timeFrame, d.Date, d.Date), CurveColor = Colors.DarkBlue, StrategyName = LocalizedStrings.YahooCandles }, YahooCandlesChart, YahooCandlesEquity, YahooCandlesPosition), }; // storage to historical data var storageRegistry = new StorageRegistry { // set historical path DefaultDrive = new LocalMarketDataDrive(HistoryPath.Folder) }; var startTime = ((DateTime)From.Value).ChangeKind(DateTimeKind.Utc); var stopTime = ((DateTime)To.Value).ChangeKind(DateTimeKind.Utc); // (ru only) ОЛ необходимо загружать с 18.45 пред дня, чтобы стаканы строились правильно if (OrderLogCheckBox.IsChecked == true) { startTime = startTime.Subtract(TimeSpan.FromDays(1)).AddHours(18).AddMinutes(45).AddTicks(1).ApplyTimeZone(TimeHelper.Moscow).UtcDateTime; } // ProgressBar refresh step var progressStep = ((stopTime - startTime).Ticks / 100).To <TimeSpan>(); // set ProgressBar bounds _progressBars.ForEach(p => { p.Value = 0; p.Maximum = 100; }); var logManager = new LogManager(); var fileLogListener = new FileLogListener("sample.log"); logManager.Listeners.Add(fileLogListener); //logManager.Listeners.Add(new DebugLogListener()); // for track logs in output window in Vusial Studio (poor performance). var generateDepths = GenDepthsCheckBox.IsChecked == true; var maxDepth = MaxDepth.Text.To <int>(); var maxVolume = MaxVolume.Text.To <int>(); var secId = security.ToSecurityId(); SetIsEnabled(false, false, false); foreach (var set in settings) { if (set.Item1.IsChecked == false) { continue; } var title = (string)set.Item1.Content; InitChart(set.Item5, set.Item6, set.Item7); var progressBar = set.Item2; var statistic = set.Item3; var emulationInfo = set.Item4; var level1Info = new Level1ChangeMessage { SecurityId = secId, ServerTime = startTime, } .TryAdd(Level1Fields.PriceStep, secCode == "RIZ2" ? 10m : 1) .TryAdd(Level1Fields.StepPrice, 6m) .TryAdd(Level1Fields.MinPrice, 10m) .TryAdd(Level1Fields.MaxPrice, 1000000m) .TryAdd(Level1Fields.MarginBuy, 10000m) .TryAdd(Level1Fields.MarginSell, 10000m); // test portfolio var portfolio = new Portfolio { Name = "test account", BeginValue = 1000000, }; // create backtesting connector var connector = new HistoryEmulationConnector( new[] { security }, new[] { portfolio }) { EmulationAdapter = { Emulator = { Settings = { // match order if historical price touched our limit order price. // It is terned off, and price should go through limit order price level // (more "severe" test mode) MatchOnTouch = false, } } }, UseExternalCandleSource = emulationInfo.UseCandleTimeFrame != null, CreateDepthFromOrdersLog = emulationInfo.UseOrderLog, CreateTradesFromOrdersLog = emulationInfo.UseOrderLog, HistoryMessageAdapter = { StorageRegistry = storageRegistry, // set history range StartDate = startTime, StopDate = stopTime, OrderLogMarketDepthBuilders = { { secId, LocalizedStrings.ActiveLanguage == Languages.Russian ? (IOrderLogMarketDepthBuilder) new PlazaOrderLogMarketDepthBuilder(secId) : new ItchOrderLogMarketDepthBuilder(secId) } } }, // set market time freq as time frame MarketTimeChangedInterval = timeFrame, }; ((ILogSource)connector).LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info; logManager.Sources.Add(connector); var candleManager = emulationInfo.UseCandleTimeFrame == null ? new CandleManager(new TradeCandleBuilderSourceEx(connector)) : new CandleManager(connector); var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame); _shortMa = new SimpleMovingAverage { Length = 10 }; _shortElem = new ChartIndicatorElement { Color = Colors.Coral, ShowAxisMarker = false, FullTitle = _shortMa.ToString() }; var chart = set.Item5; chart.AddElement(_area, _shortElem); _longMa = new SimpleMovingAverage { Length = 80 }; _longElem = new ChartIndicatorElement { ShowAxisMarker = false, FullTitle = _longMa.ToString() }; chart.AddElement(_area, _longElem); // create strategy based on 80 5-min и 10 5-min var strategy = new SmaStrategy(chart, _candlesElem, _tradesElem, _shortMa, _shortElem, _longMa, _longElem, candleManager, series) { Volume = 1, Portfolio = portfolio, Security = security, Connector = connector, LogLevel = DebugLogCheckBox.IsChecked == true ? LogLevels.Debug : LogLevels.Info, // by default interval is 1 min, // it is excessively for time range with several months UnrealizedPnLInterval = ((stopTime - startTime).Ticks / 1000).To <TimeSpan>() }; logManager.Sources.Add(strategy); connector.NewSecurities += securities => { if (securities.All(s => s != security)) { return; } // fill level1 values connector.SendInMessage(level1Info); if (emulationInfo.HistorySource != null) { if (emulationInfo.UseCandleTimeFrame != null) { connector.RegisterHistorySource(security, MarketDataTypes.CandleTimeFrame, emulationInfo.UseCandleTimeFrame.Value, emulationInfo.HistorySource); } if (emulationInfo.UseTicks) { connector.RegisterHistorySource(security, MarketDataTypes.Trades, null, emulationInfo.HistorySource); } if (emulationInfo.UseLevel1) { connector.RegisterHistorySource(security, MarketDataTypes.Level1, null, emulationInfo.HistorySource); } if (emulationInfo.UseMarketDepth) { connector.RegisterHistorySource(security, MarketDataTypes.MarketDepth, null, emulationInfo.HistorySource); } } else { if (emulationInfo.UseMarketDepth) { connector.RegisterMarketDepth(security); if ( // if order book will be generated generateDepths || // of backtesting will be on candles emulationInfo.UseCandleTimeFrame != TimeSpan.Zero ) { // if no have order book historical data, but strategy is required, // use generator based on last prices connector.RegisterMarketDepth(new TrendMarketDepthGenerator(connector.GetSecurityId(security)) { Interval = TimeSpan.FromSeconds(1), // order book freq refresh is 1 sec MaxAsksDepth = maxDepth, MaxBidsDepth = maxDepth, UseTradeVolume = true, MaxVolume = maxVolume, MinSpreadStepCount = 2, // min spread generation is 2 pips MaxSpreadStepCount = 5, // max spread generation size (prevent extremely size) MaxPriceStepCount = 3 // pips size, }); } } if (emulationInfo.UseOrderLog) { connector.RegisterOrderLog(security); } if (emulationInfo.UseTicks) { connector.RegisterTrades(security); } if (emulationInfo.UseLevel1) { connector.RegisterSecurity(security); } } // start strategy before emulation started strategy.Start(); candleManager.Start(series); // start historical data loading when connection established successfully and all data subscribed connector.Start(); }; // fill parameters panel statistic.Parameters.Clear(); statistic.Parameters.AddRange(strategy.StatisticManager.Parameters); var equity = set.Item6; var pnlCurve = equity.CreateCurve(LocalizedStrings.PnL + " " + emulationInfo.StrategyName, emulationInfo.CurveColor, EquityCurveChartStyles.Area); var unrealizedPnLCurve = equity.CreateCurve(LocalizedStrings.PnLUnreal + emulationInfo.StrategyName, Colors.Black); var commissionCurve = equity.CreateCurve(LocalizedStrings.Str159 + " " + emulationInfo.StrategyName, Colors.Red, EquityCurveChartStyles.DashedLine); var posItems = set.Item7.CreateCurve(emulationInfo.StrategyName, emulationInfo.CurveColor); strategy.PnLChanged += () => { var pnl = new EquityData { Time = strategy.CurrentTime, Value = strategy.PnL - strategy.Commission ?? 0 }; var unrealizedPnL = new EquityData { Time = strategy.CurrentTime, Value = strategy.PnLManager.UnrealizedPnL ?? 0 }; var commission = new EquityData { Time = strategy.CurrentTime, Value = strategy.Commission ?? 0 }; pnlCurve.Add(pnl); unrealizedPnLCurve.Add(unrealizedPnL); commissionCurve.Add(commission); }; strategy.PositionChanged += () => posItems.Add(new EquityData { Time = strategy.CurrentTime, Value = strategy.Position }); var nextTime = startTime + progressStep; // handle historical time for update ProgressBar connector.MarketTimeChanged += d => { if (connector.CurrentTime < nextTime && connector.CurrentTime < stopTime) { return; } var steps = (connector.CurrentTime - startTime).Ticks / progressStep.Ticks + 1; nextTime = startTime + (steps * progressStep.Ticks).To <TimeSpan>(); this.GuiAsync(() => progressBar.Value = steps); }; connector.StateChanged += () => { if (connector.State == EmulationStates.Stopped) { candleManager.Stop(series); strategy.Stop(); SetIsChartEnabled(chart, false); if (_connectors.All(c => c.State == EmulationStates.Stopped)) { logManager.Dispose(); _connectors.Clear(); SetIsEnabled(true, false, false); } this.GuiAsync(() => { if (connector.IsFinished) { progressBar.Value = progressBar.Maximum; MessageBox.Show(this, LocalizedStrings.Str3024.Put(DateTime.Now - _startEmulationTime), title); } else { MessageBox.Show(this, LocalizedStrings.cancelled, title); } }); } else if (connector.State == EmulationStates.Started) { if (_connectors.All(c => c.State == EmulationStates.Started)) { SetIsEnabled(false, true, true); } SetIsChartEnabled(chart, true); } else if (connector.State == EmulationStates.Suspended) { if (_connectors.All(c => c.State == EmulationStates.Suspended)) { SetIsEnabled(true, false, true); } } }; if (ShowDepth.IsChecked == true) { MarketDepth.UpdatingFormat = security; connector.NewMessage += message => { var quoteMsg = message as QuoteChangeMessage; if (quoteMsg != null) { MarketDepth.UpdatingQuotes = quoteMsg; } }; } _connectors.Add(connector); progressBar.Value = 0; } _startEmulationTime = DateTime.Now; // start emulation foreach (var connector in _connectors) { // raise NewSecurities and NewPortfolio for full fill strategy properties connector.Connect(); // 1 cent commission for trade connector.SendInMessage(new CommissionRuleMessage { Rule = new CommissionPerTradeRule { Value = 0.01m } }); } TabControl.Items.Cast <TabItem>().First(i => i.Visibility == Visibility.Visible).IsSelected = true; }
private void RaiseCandleSeriesProcessing(CandleSeries series, Candle candle) { CandleSeriesProcessing?.Invoke(series, candle); }
private void Chart_OnSubscribeIndicatorElement(ChartIndicatorElement element, CandleSeries series, IIndicator indicator) { _dataThreadActions.Add(() => { var chartData = new ChartDrawData(); foreach (var candle in _allCandles.CachedValues) { chartData.Group(candle.OpenTime).Add(element, indicator.Process(candle)); } Chart.Reset(new[] { element }); Chart.Draw(chartData); _indicators[element] = indicator; this.GuiAsync(() => CustomColors_Changed(null, null)); }); }
private void RaiseCandleSeriesError(CandleSeries series, MarketDataMessage reply) { CandleSeriesError?.Invoke(series, reply); }
private void RefreshCharts() { if (Dispatcher.CheckAccess()) { _dataThreadActions.Add(RefreshCharts); return; } CandleSeries series = null; this.GuiSync(() => { Chart.ClearAreas(); _areaComb = new ChartArea(); var yAxis = _areaComb.YAxises.First(); yAxis.AutoRange = true; Chart.IsAutoRange = true; Chart.IsAutoScroll = true; Chart.AddArea(_areaComb); var id = (SecurityId)Securities.SelectedItem; _security = new Security { Id = id.ToStringId(), PriceStep = id.SecurityCode.StartsWith("RI", StringComparison.InvariantCultureIgnoreCase) ? 10 : id.SecurityCode.Contains("ES") ? 0.25m : 0.01m, Board = ExchangeBoard.Associated }; _tradeGenerator = new RandomWalkTradeGenerator(id); _tradeGenerator.Init(); _tradeGenerator.Process(_security.ToMessage()); series = new CandleSeries( SeriesEditor.Settings.CandleType, _security, SeriesEditor.Settings.Arg) { IsCalcVolumeProfile = true }; _candleElement = new ChartCandleElement { FullTitle = "Candles" }; Chart.AddElement(_areaComb, _candleElement, series); _currCandle = null; _historyLoaded = false; _allCandles.Clear(); _updatedCandles.Clear(); _dataThreadActions.Clear(); }); Chart.Reset(new IChartElement[] { _candleElement }); this.GuiAsync(() => LoadData(series)); }
private void StopSeries(CandleSeries series) { var candleManager = this.GetCandleManager(); candleManager?.Stop(series); }
private void LoadData(CandleSeries series) { var msgType = series.CandleType.ToCandleMessageType(); _transactionId = _transactionIdGenerator.GetNextId(); _holder.Clear(); _holder.CreateCandleSeries(_transactionId, series); _candleTransform.Process(new ResetMessage()); _candleBuilder = msgType.ToCandleMarketDataType().CreateCandleBuilder(); var storage = new StorageRegistry(); BusyIndicator.IsBusy = true; var path = HistoryPath.Folder; var isBuild = BuildFromTicks.IsChecked == true; var format = Format.SelectedFormat; var maxDays = (isBuild || series.CandleType != typeof(TimeFrameCandle)) ? 5 : 30 * (int)((TimeSpan)series.Arg).TotalMinutes; _mdMsg = series.ToMarketDataMessage(true); Task.Factory.StartNew(() => { var date = DateTime.MinValue; if (isBuild) { foreach (var tick in storage.GetTickMessageStorage(series.Security, new LocalMarketDataDrive(path), format).Load()) { _tradeGenerator.Process(tick); if (_candleTransform.Process(tick)) { var candles = _candleBuilder.Process(_mdMsg, _currCandle, _candleTransform); foreach (var candle in candles) { _currCandle = candle; _updatedCandles.Add((CandleMessage)candle.Clone()); } } _lastTime = tick.ServerTime; if (date != tick.ServerTime.Date) { date = tick.ServerTime.Date; var str = date.To <string>(); this.GuiAsync(() => BusyIndicator.BusyContent = str); maxDays--; if (maxDays == 0) { break; } } } } else { foreach (var candleMsg in storage.GetCandleMessageStorage(msgType, series.Security, series.Arg, new LocalMarketDataDrive(path), format).Load()) { if (candleMsg.State != CandleStates.Finished) { candleMsg.State = CandleStates.Finished; } _currCandle = candleMsg; _updatedCandles.Add(candleMsg); _lastTime = candleMsg.OpenTime; if (candleMsg is TimeFrameCandleMessage) { _lastTime += (TimeSpan)series.Arg; } _tradeGenerator.Process(new ExecutionMessage { ExecutionType = ExecutionTypes.Tick, SecurityId = series.Security.ToSecurityId(), ServerTime = _lastTime, TradePrice = candleMsg.ClosePrice, }); if (date != candleMsg.OpenTime.Date) { date = candleMsg.OpenTime.Date; var str = date.To <string>(); this.GuiAsync(() => BusyIndicator.BusyContent = str); maxDays--; if (maxDays == 0) { break; } } } } _historyLoaded = true; }) .ContinueWith(t => { if (t.Exception != null) { Error(t.Exception.Message); } BusyIndicator.IsBusy = false; Chart.IsAutoRange = false; }, TaskScheduler.FromCurrentSynchronizationContext()); }
/// <summary> /// To add data for the candle. /// </summary> /// <param name="series">Candles series.</param> /// <param name="candle">The candle for which you need to add data.</param> /// <param name="value">New data.</param> public void AddValue(CandleSeries series, Candle candle, ICandleBuilderSourceValue value) { if (_valuesKeepTime == TimeSpan.Zero) return; GetInfo(series).AddValue(candle, value); }
/// <summary> /// subscribe to receive candle /// подписаться на получение свечек /// </summary> private void Subscrable() { try { while (true) { Thread.Sleep(50); if (_neadToStopThread) { return; } if (ServerType == ServerType.None || string.IsNullOrWhiteSpace(NamePaper)) { continue; } List <IServer> servers = ServerMaster.GetServers(); if (servers == null) { if (ServerType != ServerType.None) { ServerMaster.SetNeedServer(ServerType); } continue; } try { if (ServerType == ServerType.Optimizer && this.ServerUid != 0) { for (int i = 0; i < servers.Count; i++) { if (servers[i].ServerType == ServerType.Optimizer && ((OptimizerServer)servers[i]).NumberServer == this.ServerUid) { _myServer = servers[i]; break; } } } else { _myServer = servers.Find(server => server.ServerType == ServerType); } } catch { // ignore continue; } if (_myServer == null) { if (ServerType != ServerType.None) { ServerMaster.SetNeedServer(ServerType); } continue; } else { SubscribleOnServer(_myServer); if (_myServer.ServerType == ServerType.Tester) { ((TesterServer)_myServer).TestingEndEvent -= ConnectorReal_TestingEndEvent; ((TesterServer)_myServer).TestingEndEvent += ConnectorReal_TestingEndEvent; } } Thread.Sleep(50); ServerConnectStatus stat = _myServer.ServerStatus; if (stat != ServerConnectStatus.Connect) { continue; } lock (_subscrableLocker) { if (_mySeries == null) { while (_mySeries == null) { if (_neadToStopThread) { return; } Thread.Sleep(100); _mySeries = _myServer.StartThisSecurity(_namePaper, TimeFrameBuilder); if (_mySeries == null && _myServer.ServerType == ServerType.Optimizer && ((OptimizerServer)_myServer).NumberServer != ServerUid) { for (int i = 0; i < servers.Count; i++) { if (servers[i].ServerType == ServerType.Optimizer && ((OptimizerServer)servers[i]).NumberServer == this.ServerUid) { UnSubscribleOnServer(_myServer); _myServer = servers[i]; SubscribleOnServer(_myServer); break; } } } } _mySeries.СandleUpdeteEvent += MySeries_СandleUpdeteEvent; _mySeries.СandleFinishedEvent += MySeries_СandleFinishedEvent; _subscrabler = null; } } _subscrabler = null; if (SecuritySubscribeEvent != null) { SecuritySubscribeEvent(Security); } return; } } catch (Exception error) { SendNewLogMessage(error.ToString(), LogMessageType.Error); } }
private SeriesInfo GetInfo(CandleSeries series) { if (series == null) throw new ArgumentNullException("series"); var info = _info.TryGetValue(series); if (info == null) throw new InvalidOperationException(LocalizedStrings.Str648Params.Put(series)); return info; }
/// <summary> /// 追加K线 /// </summary> /// <returns></returns> public CandleSeries AddCandle(string candleName, string openfield, string highfield, string lowfield, string closefield, int panelID, bool displayTitleField) { if (openfield == null || highfield == null || lowfield == null || closefield == null) { return null; } if (this.dtAllMsg.Columns.Contains(openfield) || this.dtAllMsg.Columns.Contains(highfield) || this.dtAllMsg.Columns.Contains(lowfield) || this.dtAllMsg.Columns.Contains(closefield)) { return null; } if (this.dicChartPanel.ContainsKey(panelID)) { ChartPanel chartPanel = this.dicChartPanel[panelID]; CandleSeries candleSeries = new CandleSeries(); candleSeries = new CandleSeries(); candleSeries.CandleName = candleName; candleSeries.OpenField = openfield; candleSeries.HighField = highfield; candleSeries.LowField = lowfield; candleSeries.CloseField = closefield; chartPanel.YScaleField.AddRange(new string[] { openfield, highfield, lowfield, closefield }); candleSeries.Down_Color = Color.SkyBlue; candleSeries.Up_Color = Color.Red; candleSeries.DisplayTitleField = displayTitleField; DataColumn dcOpen = new DataColumn(openfield); DataColumn dcHigh = new DataColumn(highfield); DataColumn dcLow = new DataColumn(lowfield); DataColumn dcClose = new DataColumn(closefield); this.dtAllMsg.Columns.Add(dcOpen); this.dtAllMsg.Columns.Add(dcHigh); this.dtAllMsg.Columns.Add(dcLow); this.dtAllMsg.Columns.Add(dcClose); chartPanel.CandleSeriesList.Add(candleSeries); return candleSeries; } return null; }