← Voltar

Урок 4. Свечи, графики, история

Видео-уроки (основное): Свечи, индикаторы, стратегия, метки, вывод на график

[vk]http://vk.com/video_ext.php?oid=-66650972&id=167470235&hash=5354329b0f44e11a&hd=3[/vk]

Исторические свечи, стратегия, вывод на график

[vk]http://vk.com/video_ext.php?oid=-66650972&id=167470340&hash=d4a2baaf8c533bc8&hd=3[/vk]

Видео-уроки (экстра): Создание и работа с кластерными свечками

[vk]http://vk.com/video_ext.php?oid=-66650972&id=167470847&hash=05646cb903828f2e&hd=3[/vk]

Темы занятия:

Свечи (S# документация)

  1. Получение свечей из торгового терминала
  2. Вывод свечного графика Индикаторы (S# документация)
  3. Создание простого собственного индикатора
  4. Вывод графика индикатора Стратегия (S# документация)
  5. Получение заявок и сделок
  6. Вывод меток заявок и сделок на график Работа с графиком (SciChart)
  7. Работа с областями графика
  8. Создание и использование графических элементов Создание модуля для получения исторических данных Создание сборки с получением исторических свечей, отрисовкой графиков и запуском стратегии Выводим свечной график в S#.Studio

Домашнее задание: В проекте с получением и отображением исторических свечей, сделать вывод меток заявок и сделок на график.

Полезные ссылки: Свечи, документация

Вложения: Скачать проекты

Изменения в проектах:

Проект CandlesDownload Файл History.cs и SimpleSecurityStorage.cs

Было:


using StockSharp.Algo.History.Finam;

Стало:


using StockSharp.Algo.History.Russian.Finam;

Файл SimpleSecurityStorage.cs

В версии S# 4.1.19.1 интерфейс ISecurityStorage содержит свойство Securities, поэтому класс SimpleSecurityStorage, его должен реализовать.

Было:


    /// <summary>
    /// Простое хранилище
    /// </summary>
    class SimpleSecurityStorage:ISecurityStorage 
    {
	private readonly SynchronizedDictionary<long, Security> _cacheByFinamId = new 

SynchronizedDictionary<long, Security>();

	public Security LoadBy(string fieldName, object fieldValue)
		{
			return _cacheByFinamId.TryGetValue((long)fieldValue);
		}

        public IEnumerable<Security> Lookup(Security criteria)
                {
                        throw new NotImplementedException();
                }

        public void Save(Security security)
		{
			TryAddToCache(security);
		}

		private void TryAddToCache(Security security)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			var finamId = security.ExtensionInfo.TryGetValue(FinamHistorySource.FinamSecurityIdField);

			if (finamId != null)
				_cacheByFinamId.SafeAdd((long)finamId, key => security);
		}
    }

Стало:


    /// <summary>
    /// Простое хранилище
    /// </summary>
    class SimpleSecurityStorage:ISecurityStorage 
    {
	private readonly SynchronizedDictionary<long, Security> _cacheByFinamId = new 

SynchronizedDictionary<long, Security>();
        private IEnumerable<Security> _securities;

        public Security LoadBy(string fieldName, object fieldValue)
		{
			return _cacheByFinamId.TryGetValue((long)fieldValue);
		}

        public IEnumerable<Security> Lookup(Security criteria)
        	{
            		throw new NotImplementedException();
        	}

        public IEnumerable<Security> Securities
        {
            get { return _securities; }
        }

        public void Save(Security security)
		{
			TryAddToCache(security);
		}

	private void TryAddToCache(Security security)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			var finamId = security.ExtensionInfo.TryGetValue(FinamHistorySource.FinamSecurityIdField);

			if (finamId != null)
				_cacheByFinamId.SafeAdd((long)finamId, key => security);
		}
    }

Проект CandlesDownloadUsing Файл BollingerStrategy.cs

Теперь класс Strategy не имеет свойства PendingOrders, все Pending заявки можно получить из общей коллекции Orders, поэтому избыточность в библиотеке была устранена, и мы в соем проекте теперь используем коллекцию Orders, и в ней, анализируя свойство State каждой заявки, используя Linq выражение.

Было:



        /// <summary>
        /// Возвращает true если нет активных заявок, а противном случае возвращает false
        /// </summary>
        private bool NoActiveOrders
        {
            get
            {
                return Orders.Count(o => o.State != OrderStates.Done) == 0 && PendingOrders.Count() == 0;
            }
        }

Стало:


        /// <summary>
        /// Возвращает true если нет активных заявок, а противном случае возвращает false
        /// </summary>
        private bool NoActiveOrders
        {
            get
            {
                return Orders.Count(o => o.State != OrderStates.Done) == 0 && Orders.Where(o=>o.State == 

OrderStates.Pending).Count() == 0;
            }
        }

Файл MainWindow.cs

Начиная с версии S# 4.1.19.1 статус подключения коннектора вынесен в специальное свойство ConnectionState, которое может принимать следующие значения: Disconnected - Не активно, Disconnecting - В процессе отключения, Connected - В процессе подключения, Connecting - Подключение активно, Failed - Ошибка подключения

Таким образом, теперь нет свойства IsConnected, а наличие статуса подключения мы можем получать от свойства ConnectionState.

Было:


        /// <summary>
        /// Обработчик события закрытия окна
        /// </summary>
        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            if (Connection.SafeConnection.Trader != null && Connection.SafeConnection.Trader.IsConnected)
            {
                Connection.SafeConnection.Trader.Dispose();
            }
            Thread.CurrentThread.Abort();
            base.OnClosing(e);
        }

Стало:


        /// <summary>
        /// Обработчик события закрытия окна
        /// </summary>
        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            if (Connection.SafeConnection.Trader != null && Connection.SafeConnection.Trader.ConnectionState == 

ConnectionStates.Connected)
            {
                Connection.SafeConnection.Trader.Dispose();
            }
            Thread.CurrentThread.Abort();
            base.OnClosing(e);
        }

Este tópico foi útil?

Compartilhar tópico

Comentários (59)

Entrar ou Criar conta, Faça login ou cadastre-se para deixar um comentário

UsilaDobry
UsilaDobry

Увидел в Вас в примере код свойства:

private bool NoActiveOrders
 {  get { return Orders.Count(o => o.State != OrderStates.Done) == 0 && PendingOrders.Count() == 0; } }

Я бы его написал вот так

private bool NoActiveOrders { get { return Orders.Count(o => o.State == OrderStates.Active) == 0; } }

А в чем замысел?

UsilaDobry
UsilaDobry

Что-то я не пойму, как мне коллекцию свечей из метода GetHistoryCandles(); передать в метод ProcessCandle(CandleSeries series, Candle candle)?.. В уроке метод Draw(Candle), принимает только свечи, а у меня при выводе на график ProcessCandle(CandleSeries series, Candle candle) принимает еще и серию свечей... В моем варианте использовать метод GetHistoryCandles() не получится?

private void ChartButton_Click(object sender, RoutedEventArgs e)
        {
                
                if (TpTimeFrame.Value == null)
                {
                    MessageBox.Show("Введите значение таймфрейм");
                    return;
                }
                
                var timeFrame = TpTimeFrame.Value.Value.TimeOfDay;
                
                GetHistoryCandles();???????
                
                RunProcessGetCandles(timeFrame);
                ChartButton.Content = "Очистить график";
         }
        /// <summary>
        /// Исторические свечки
        /// </summary>
        /// <returns>Коллекция свечей</returns>
        private IEnumerable<Candle> GetHistoryCandles()
        {
            try
            {
                if (SourceHistoryComboBox.SelectedIndex == 0)
                {
                   //закачка с сайта финама
                   return Finam.History.GetHistoryCandles(
                       ConnectionInterface.SelectedSecurity,
                       TpTimeFrame.Value.Value.TimeOfDay,
                       BeginDataPicker.SelectedDate.Value,
                       EndDataPicker.SelectedDate.Value);
                }
                else
                return new Candle[0];
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to retrive historical candles. " + ex.Message);
                return new Candle[0];
            }
        }
         
        /// <summary>
        /// Метод инициирования среды для получения свечей и дальнейшей отрисовки
        /// </summary>
        /// <param name="timeFrame">Тайм-фрейм для свечей</param>
        private void RunProcessGetCandles(TimeSpan timeFrame)
        {
            _candleManager = new CandleManager(ConnectionInterface.SafeConnection.Trader);

            var security = ConnectionInterface.SelectedSecurity;

            var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);
            series.WorkingTime.Times[0].Min = TimeSpan.FromHours(0);
            series.WorkingTime.Times[0].Max = TimeSpan.FromHours(23);
            
            _candleManager.Processing += ProcessCandle;
            
            _candleManager.Start(series);
        }

        private void ProcessCandle(CandleSeries series, Candle candle)
        {
            try
            {
                if (candle.State == CandleStates.Finished)
                {
                    var valueSar = _chartParabolicElement.Indicator.Process(new CandleIndicatorValue(candle) { IsFinal = true });
                    var valueBb = _chartBollingerElement.Indicator.Process(new CandleIndicatorValue(candle) { IsFinal = true });
                    this.GuiAsync(() => Chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
                {
                    {_chartCandleElement, candle},
                    {_chartParabolicElement, new ChartIndicatorValue(_chartParabolicElement.Indicator, valueSar)},
                    {_chartBollingerElement, new ChartIndicatorValue(_chartBollingerElement.Indicator, valueBb)}
                }));
                }
                else
                {
                    this.GuiAsync(() => Chart.ProcessCandle(_chartCandleElement, candle));
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.ToString());
            }
        }
IvanB
IvanB Autor

UsilaDobry: Что-то я не пойму, как мне коллекцию свечей из метода GetHistoryCandles(); передать в метод ProcessCandle(CandleSeries series, Candle candle)?.. В уроке метод Draw(Candle), принимает только свечи, а у меня при выводе на график ProcessCandle(CandleSeries series, Candle candle) принимает еще и серию свечей... В моем варианте использовать метод GetHistoryCandles() не получится?

private void ChartButton_Click(object sender, RoutedEventArgs e)
        {
                
                if (TpTimeFrame.Value == null)
                {
                    MessageBox.Show("Введите значение таймфрейм");
                    return;
                }
                
                var timeFrame = TpTimeFrame.Value.Value.TimeOfDay;
                
                GetHistoryCandles();???????
                
                RunProcessGetCandles(timeFrame);
                ChartButton.Content = "Очистить график";
         }
        /// <summary>
        /// Исторические свечки
        /// </summary>
        /// <returns>Коллекция свечей</returns>
        private IEnumerable<Candle> GetHistoryCandles()
        {
            try
            {
                if (SourceHistoryComboBox.SelectedIndex == 0)
                {
                   //закачка с сайта финама
                   return Finam.History.GetHistoryCandles(
                       ConnectionInterface.SelectedSecurity,
                       TpTimeFrame.Value.Value.TimeOfDay,
                       BeginDataPicker.SelectedDate.Value,
                       EndDataPicker.SelectedDate.Value);
                }
                else
                return new Candle[0];
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to retrive historical candles. " + ex.Message);
                return new Candle[0];
            }
        }
         
        /// <summary>
        /// Метод инициирования среды для получения свечей и дальнейшей отрисовки
        /// </summary>
        /// <param name="timeFrame">Тайм-фрейм для свечей</param>
        private void RunProcessGetCandles(TimeSpan timeFrame)
        {
            _candleManager = new CandleManager(ConnectionInterface.SafeConnection.Trader);

            var security = ConnectionInterface.SelectedSecurity;

            var series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);
            series.WorkingTime.Times[0].Min = TimeSpan.FromHours(0);
            series.WorkingTime.Times[0].Max = TimeSpan.FromHours(23);
            
            _candleManager.Processing += ProcessCandle;
            
            _candleManager.Start(series);
        }

        private void ProcessCandle(CandleSeries series, Candle candle)
        {
            try
            {
                if (candle.State == CandleStates.Finished)
                {
                    var valueSar = _chartParabolicElement.Indicator.Process(new CandleIndicatorValue(candle) { IsFinal = true });
                    var valueBb = _chartBollingerElement.Indicator.Process(new CandleIndicatorValue(candle) { IsFinal = true });
                    this.GuiAsync(() => Chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
                {
                    {_chartCandleElement, candle},
                    {_chartParabolicElement, new ChartIndicatorValue(_chartParabolicElement.Indicator, valueSar)},
                    {_chartBollingerElement, new ChartIndicatorValue(_chartBollingerElement.Indicator, valueBb)}
                }));
                }
                else
                {
                    this.GuiAsync(() => Chart.ProcessCandle(_chartCandleElement, candle));
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.ToString());
            }
        }

Можно сделать так:


foreach (var candle in GetHistoryCandles())
{
   ProcessCandle(null, candle);
}

В методе ProcessCandle Вы не используете аргумент CandleSeries series, можно подписаться на получение свечей так: series.ProcessCandle += ProcessCandle; в место этого: _candleManager.Processing += ProcessCandle; и изменить заголовок метода: private void ProcessCandle(Candle candle)

тогда получать свечи можно так:


foreach (var candle in GetHistoryCandles())
{
   ProcessCandle(candle);
}

UsilaDobry
UsilaDobry

IvanB: В методе ProcessCandle Вы не используете аргумент CandleSeries series, можно подписаться на получение свечей так: series.ProcessCandle += ProcessCandle; в место этого: _candleManager.Processing += ProcessCandle; и изменить заголовок метода: private void ProcessCandle(Candle candle)

тогда получать свечи можно так:

foreach (var candle in GetHistoryCandles()) { ProcessCandle(candle); }


Может в таком случае можно не использовать foreach, а сделать как в видео-уроке

```csharp
GetHistoryCandles().ForEach(ProcessCandle);

но я не могу этого сейчас испробовать, поскольку срок на демосервер истек, а новые ключи вчера получил, но они не прокатывают. Написал письмо в техподдержку Квика, пока молчат... Процесс остановился 😀 Наконец-то подключили... Проверил, такой вариант работает, но график индикаторов выводит не корректно...

UsilaDobry
UsilaDobry

И таким способом

foreach (var candle in GetHistoryCandles())
{
   ProcessCandle(null, candle);
}

и таким способом

GetHistoryCandles().ForEach(ProcessCandle);

история выводится корректно, и свечи и индикаторы, но склейка получается неправильная... например при выводе реальной свечи на 10 минутном графике после свечи 12:10 рисуется свеча 12:45, потом после Finished становится свечой 12:20. Также в месте склейки искажаются индикаторы...На истории индикаторы переходят из одного дня в другой плавно, а в месте склейки идёт явный разрыв значений... Что можно придумать...?

IvanB
IvanB Autor

UsilaDobry: И таким способом

foreach (var candle in GetHistoryCandles()) { ProcessCandle(null, candle); }

> и таким способом
> ```csharp
GetHistoryCandles().ForEach(ProcessCandle);

история выводится корректно, и свечи и индикаторы, но склейка получается неправильная... например при выводе реальной свечи на 10 минутном графике после свечи 12:10 рисуется свеча 12:45, потом после Finished становится свечой 12:20. Также в месте склейки искажаются индикаторы...На истории индикаторы переходят из одного дня в другой плавно, а в месте склейки идёт явный разрыв значений... Что можно придумать...?

Если учесть то, что в демо квике данные поступают со сдвигом во времени, и учесть что исторические данные мы качаем реальные, которые были, то тогда становится понятно почему склейка получается "кривая". Т.е. причина в демо данных, которые никак не состыкуются с реальной историей.

Bond
Bond

UsilaDobry: И таким способом

foreach (var candle in GetHistoryCandles()) { ProcessCandle(null, candle); }

> и таким способом
> ```csharp
GetHistoryCandles().ForEach(ProcessCandle);

история выводится корректно, и свечи и индикаторы, но склейка получается неправильная... например при выводе реальной свечи на 10 минутном графике после свечи 12:10 рисуется свеча 12:45, потом после Finished становится свечой 12:20. Также в месте склейки искажаются индикаторы...На истории индикаторы переходят из одного дня в другой плавно, а в месте склейки идёт явный разрыв значений... Что можно придумать...?

Добрый день UsilaDobry! Обратил внимание на ваш скриншот. Любопытная реализация приложения. Тестер и работа в риалтайме одновременно. Плюс выделение графика в отдельную вкладку. Очень интересно как вы реализовали очистку графика и отображение подсказок и меток на графике! Если это не большой секрет будет здорово, если вы поделитесь опытом реализации и по возможности фрагментами кода. Спасибо!

pft_man
pft_man

А какие ещё темы есть в SciChart.ChartTheme, кроме ExpressionDark? Я искал в документации и на форуме, но ничего не нашёл.

UsilaDobry
UsilaDobry

pft_man: А какие ещё темы есть в SciChart.ChartTheme, кроме ExpressionDark? Я искал в документации и на форуме, но ничего не нашёл.

Доступные темы: ExpressionLight, ExpressionDark, BlackSteel, BrightSpark, Chrome, Electric, Oscilloscope

pft_man
pft_man

Спасибо.

pft_man
pft_man

А как нарисовать на графике свой трейлинг-стоп так, чтобы он ещё и на истории показывался? В Wealth-Lab для этого существует метод PlotStops(), который просто рисует стопы, а я рассчитываю сами значения стопов.

Единственный вариант - сделать свой индикатор, рассчитывающий трейлинг-стоп, так? Такой индикатор будет иметь значение IsFormed, когда есть позиция. То есть он привязан к стратегии. Как лучше это в коде организовать?

И есть ли свойство у ChartIndicatorElement, позволяющее рисовать не линии, а точки, например. Если нет, то как можно это сделать?

IvanB
IvanB Autor

pft_man: А как нарисовать на графике свой трейлинг-стоп так, чтобы он ещё и на истории показывался? В Wealth-Lab для этого существует метод PlotStops(), который просто рисует стопы, а я рассчитываю сами значения стопов.

Единственный вариант - сделать свой индикатор, рассчитывающий трейлинг-стоп, так? Такой индикатор будет иметь значение IsFormed, когда есть позиция. То есть он привязан к стратегии. Как лучше это в коде организовать?

И есть ли свойство у ChartIndicatorElement, позволяющее рисовать не линии, а точки, например. Если нет, то как можно это сделать?

Можно использовать метки заявок и сделок. Для отрисовки индикатора можно выбирать стиль, свойство ChartIndicatorElement.DrawStyle, можно попробовать использовать тип ChartIndicatorDrawStyles.Dot для Вашей цели. Можно создать свой графический элемент (метка, аналог метке-заявке или метке-сделке)

pft_man
pft_man

Ещё один вопрос. Cледующий код по событию изменения свечки:

if ((candle.State == CandleStates.Finished) && (_series.GetCandle<Candle>(0).HighPrice > _series.GetCandle<Candle>(1).HighPrice))

Когда придёт новая цена, которая закроет текущую свечку (возвратит ей статуc finished), какая свечка будет считаться текущей: которая получила статус finished или следующая с первой ценой. Ведь по сути эта цена должна уже начать формировать следующую свечку. То есть обращаться к завершившейся свечке нужно будет через индекс 0 (как у меня в коде) или уже через 1? В общем, мне нужно, чтобы как только свечка завершится, её High сравнивался с High предыдущей свечки. Мой код будет правильно работать?

IvanB
IvanB Autor

pft_man: Ещё один вопрос. Cледующий код по событию изменения свечки:

if ((candle.State == CandleStates.Finished) && (_series.GetCandle<Candle>(0).HighPrice > _series.GetCandle<Candle>(1).HighPrice))

> Когда придёт новая цена, которая закроет текущую свечку (возвратит ей статуc finished), какая свечка будет считаться текущей: которая получила статус finished или следующая с первой ценой. Ведь по сути эта цена должна уже начать формировать следующую свечку. То есть обращаться к завершившейся свечке нужно будет через индекс 0 (как у меня в коде) или уже через 1?
> В общем, мне нужно, чтобы как только свечка завершится, её High сравнивался с High предыдущей свечки. Мой код будет правильно работать?

Да, Ваш код будет работать, учитывайте что событие обработки свечей передает в обработчик последовательно все свечи, в том числе, как только заканчивается свеча, она передается в обработчик, и только при следующем вызове обработчика будет передана новая открытая свеча.
UsilaDobry
UsilaDobry

Доброго вечера Иван. Столкнулся с такой ошибкой при закачке истории с Финама "Элемент с таким ключом уже был запущен". Такая ошибка у меня появляется, когда я запускаю два графика с историей с разными таймфреймами. Первый график выводит историю и реал корректно, а второй график выдает такую ошибку и выводит только реал... Почему, ведь происходит обращение к сайту Финама для получения свечек с разным таймфреймом...?

private IEnumerable<Candle> GetHistoryCandles1()
        {
            try
            {
                    //закачка с сайта финама
                    if (TpTimeFrame1.Value != null)
                        if (BeginDataPicker.SelectedDate != null)
                            if (EndDataPicker.SelectedDate != null)
                                return Finam.History.GetHistoryCandles(
                                    ConnectionInterface.SelectedSecurity,
                                    TpTimeFrame1.Value.Value.TimeOfDay,
                                    BeginDataPicker.SelectedDate.Value,
                                    EndDataPicker.SelectedDate.Value);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to retrive historical candles. " + ex.Message);
                return new Candle[0];
            }
            return null;
        }
private IEnumerable<Candle> GetHistoryCandles2()
        {
            try
            {
                //закачка с сайта финама
                if (TpTimeFrame2.Value != null)
                    if (BeginDataPicker.SelectedDate != null)
                        if (EndDataPicker.SelectedDate != null)
                            return Finam.History.GetHistoryCandles(
                                ConnectionInterface.SelectedSecurity,
                                TpTimeFrame2.Value.Value.TimeOfDay,
                                BeginDataPicker.SelectedDate.Value,
                                EndDataPicker.SelectedDate.Value);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to retrive historical candles. " + ex.Message);
                return new Candle[0];
            }
            return null;
        }
IvanB
IvanB Autor

UsilaDobry: Доброго вечера Иван. Столкнулся с такой ошибкой при закачке истории с Финама "Элемент с таким ключом уже был запущен". Такая ошибка у меня появляется, когда я запускаю два графика с историей с разными таймфреймами. Первый график выводит историю и реал корректно, а второй график выдает такую ошибку и выводит только реал... Почему, ведь происходит обращение к сайту Финама для получения свечек с разным таймфреймом...?

private IEnumerable<Candle> GetHistoryCandles1()
        {
            try
            {
                    //закачка с сайта финама
                    if (TpTimeFrame1.Value != null)
                        if (BeginDataPicker.SelectedDate != null)
                            if (EndDataPicker.SelectedDate != null)
                                return Finam.History.GetHistoryCandles(
                                    ConnectionInterface.SelectedSecurity,
                                    TpTimeFrame1.Value.Value.TimeOfDay,
                                    BeginDataPicker.SelectedDate.Value,
                                    EndDataPicker.SelectedDate.Value);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to retrive historical candles. " + ex.Message);
                return new Candle[0];
            }
            return null;
        }
private IEnumerable<Candle> GetHistoryCandles2()
        {
            try
            {
                //закачка с сайта финама
                if (TpTimeFrame2.Value != null)
                    if (BeginDataPicker.SelectedDate != null)
                        if (EndDataPicker.SelectedDate != null)
                            return Finam.History.GetHistoryCandles(
                                ConnectionInterface.SelectedSecurity,
                                TpTimeFrame2.Value.Value.TimeOfDay,
                                BeginDataPicker.SelectedDate.Value,
                                EndDataPicker.SelectedDate.Value);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unable to retrive historical candles. " + ex.Message);
                return new Candle[0];
            }
            return null;
        }

Измените класс History на это:


    public class History : FinamHistorySource
    {
        public History(ISecurityStorage securityStorage) : base(securityStorage)
        {
        }

        /// <summary>
        /// Все инструменты у источника финама
        /// </summary>
        private IEnumerable<FinamSecurityInfo> Securities { get { return DownloadSecurityInfo(); } }
        public IEnumerable<Candle> GetHistoryCandles(Security security, TimeSpan timeFrame, DateTime from, DateTime to)
        {
            //находим финамовский инструмент по коду инструмента
            var fi = Securities.FirstOrDefault(f => f.Code == security.Code);

            var marketId = new KeyValuePair<object, object>(FinamMarketIdField, fi.FinamMarketId);
            var securityId = new KeyValuePair<object, object>(FinamSecurityIdField, fi.FinamSecurityId);

            if (!security.ExtensionInfo.Contains(marketId) && !security.ExtensionInfo.Contains(securityId))
            {
                //добавляем дополнительную информацию в инструмент, чтобы получить свечки через основной метод GetCandles()
                security.ExtensionInfo.Add(marketId); //идентификатор секции рынка
                security.ExtensionInfo.Add(securityId); //идентификатор инструмента
            }

            //запрашиваем свечки
            return GetCandles(security, from, to, timeFrame);
        }

UsilaDobry
UsilaDobry

Еще вопрос по обработке исторических свечей. Для того, чтобы обработать свечи с начала торговой сессии и до времени запуска стратегии я использую вот такое условие:

if (candle.CloseTime <= StartedTime && _parabolic.IsFormed &&
                        candle.State == CandleStates.Finished)

Необходимо получить исторические свечи + свечи с начала торговой сессии и до времени старта стратегии для обработки и определения торговых моделей. А как передать исторические свечи в стратегию?

IvanB
IvanB Autor

UsilaDobry: Еще вопрос по обработке исторических свечей. Для того, чтобы обработать свечи с начала торговой сессии и до времени запуска стратегии я использую вот такое условие:

if (candle.CloseTime <= StartedTime && _parabolic.IsFormed && candle.State == CandleStates.Finished)

> Необходимо получить исторические свечи + свечи с начала торговой сессии и до времени старта стратегии для обработки и определения торговых моделей.
> А как передать исторические свечи в стратегию?

Вообще, зависит от того, как Вы реализовали стратегию.
Думаю, лучшим вариантом будет - создать специальный метод в стратегии, который будет принимать свечи, и этот метод будет реализовывать то, что нужно делать с переданными свечами в Вашей стратегии.
UsilaDobry
UsilaDobry

Доброго дня!

Пробую добавить вывод реальных свечей от Альфа-коннектора, появляется ошибка "Параметр свечки 00-10-00 неправильный" в строке _candleManager.Start(series); Причем здесь параметр свечки, если в менеджер свечей передается серия свечей, и почему параметр серии 10 минут неправильный?..

using System;
using System.Collections.Generic;
using System.Windows;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using Ecng.Common;
using Ecng.Collections;
using Ecng.ComponentModel;
using Ecng.Xaml;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Indicators.Trend;
using StockSharp.BusinessEntities;
using StockSharp.AlfaDirect;
using StockSharp.Logging;
using StockSharp.Xaml;
using StockSharp.Xaml.Charting;

namespace MARKET_SUCCESS_ALFA
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        private AlfaTrader _trader;
        private CandleManager _candleManager;
        private CandleSeries _series;
        private bool _isExportStarted;
        private readonly ObservableCollection<Security> _securitiesSource = new ObservableCollection<Security>();
        private readonly ObservableCollection<Portfolio> _portfoliosSource = new ObservableCollection<Portfolio>();

        private readonly LogManager _logManager = new LogManager();
        private readonly MonitorWindow _monitor = new MonitorWindow();

        //окно для отображения графика со свечками
        private ChartWindow _chartWindow;
        private ChartCandleElement _candlesElem;
        private ChartIndicatorElement _chartBollingerElement; 

        public MainWindow()
        {
            InitializeComponent();

            var items = HistoryInterval.Items;
            items.Add(new ComboBoxItem { Content = "1 минута", Tag = AlfaTimeFrames.Minute1 });
            items.Add(new ComboBoxItem { Content = "5 минут", Tag = AlfaTimeFrames.Minute5 });
            items.Add(new ComboBoxItem { Content = "10 минут", Tag = AlfaTimeFrames.Minute10 });
            items.Add(new ComboBoxItem { Content = "15 минут", Tag = AlfaTimeFrames.Minute15 });
            items.Add(new ComboBoxItem { Content = "30 минут", Tag = AlfaTimeFrames.Minute30 });
            items.Add(new ComboBoxItem { Content = "1 час", Tag = AlfaTimeFrames.Hour });
            items.Add(new ComboBoxItem { Content = "День", Tag = AlfaTimeFrames.Day });
            items.Add(new ComboBoxItem { Content = "Неделя", Tag = AlfaTimeFrames.Week });
            items.Add(new ComboBoxItem { Content = "Месяц", Tag = AlfaTimeFrames.Month });
            items.Add(new ComboBoxItem { Content = "Год", Tag = AlfaTimeFrames.Year });

            HistoryInterval.SelectedIndex = 2;
            
            From.Value = DateTime.Today - TimeSpan.FromDays(7);
            To.Value = DateTime.Today;

            Security.ItemsSource = _securitiesSource;
            Portfolio.ItemsSource = _portfoliosSource;

            _logManager.Listeners.Add(new FileLogListener());
            _logManager.Listeners.Add(new GuiLogListener(_monitor));
            _monitor.Show();
        }

        private void ConnectClick(object sender, RoutedEventArgs e)
        {
            // создаем шлюз
            _trader = new AlfaTrader();

            _logManager.Sources.Add(_trader);

            _trader.ProcessDataError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), "Ошибка обработки данных"));
            _trader.NewSecurities += securities =>
            {
                this.GuiAsync(() => _securitiesSource.AddRange(securities));

                // начинаем получать текущие сделки (для построения свечек в реальном времени)
                securities.ForEach(_trader.RegisterTrades);
            };
            _trader.NewPortfolios += portfolios => this.GuiAsync(() => _portfoliosSource.AddRange(portfolios));
            _trader.Connected += () => this.GuiAsync(() =>
            {
                ExportBtn.IsEnabled = true;
                ConnectBtn.IsEnabled = false;
            });

            _trader.Connect();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            if (_trader != null)
            {
                if (_isExportStarted)
                    StopExport();

                _logManager.Sources.Remove(_trader);

                _trader.Dispose();
            }

            base.OnClosing(e);
        }

        private void StartExport()
        {
            _isExportStarted = true;
            _trader.StartExport();
        }

        private void StopExport()
        {
            _trader.StopExport();
            _isExportStarted = false;
        }

        private void ExportClick(object sender, RoutedEventArgs e)
        {
            if (_isExportStarted)
                StopExport();
            else
                StartExport();
        }

        private Security SelectedSecurity
        {
            get { return (Security)Security.SelectedValue; }
        }

        private Portfolio SelectedPortfolio
        {
            get { return (Portfolio)Portfolio.SelectedValue; }
        }

        private void SecuritySelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ShowChart.IsEnabled = SelectedSecurity != null;
        }

        private void PortfolioSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            TradingBtn.IsEnabled = SelectedPortfolio != null;
        }
        private void ShowChartClick(object sender, RoutedEventArgs e)
        {
            var security = SelectedSecurity;

            var timeFrame = (AlfaTimeFrames)((ComboBoxItem)HistoryInterval.SelectedItem).Tag;

            if (From.Value != null)
            {
                var from = From.Value.Value;
                if (To.Value != null)
                {
                    var to = To.Value.Value;

                    if (@from > to)
                    {
                        return;
                    }

                    var candles = _trader.GetHistoryData(security, timeFrame, new Range<DateTime>(@from, to));
                    
                    _chartWindow = new ChartWindow
                    {
                        Title = "{0}, {1}, {2} - {3}".Put(security.Code,
                                                          ((ComboBoxItem)HistoryInterval.SelectedItem).Content,
                                                          @from.ToString(CultureInfo.InvariantCulture), to.ToString(CultureInfo.InvariantCulture))
                    };

                    var area = new ChartArea();
                    _chartWindow.Chart.ChartTheme = "ExpressionDark";
                    _chartWindow.Chart.IsAutoScroll = true;
                    _chartWindow.Chart.Areas.Add(area);

                    _candlesElem = new ChartCandleElement
                    {
                        Antialiasinig = false,
                        UpBodyColor = Colors.Chartreuse,
                        UpWickColor = Colors.Chartreuse,
                        DownBodyColor = Colors.Red,
                        DownWickColor = Colors.Red,
                        IsLegend = true,
                    };

                    _chartBollingerElement = new ChartIndicatorElement
                    {
                        Antialiasinig = false,
                        Color = Colors.DeepSkyBlue,
                        IsLegend = true,
                        Indicator = new BollingerBands
                        {
                            Length = 20,
                            Width = 2
                        },
                        Title = "Bollinger Bands",
                        DrawStyle = ChartIndicatorDrawStyles.Line,
                    };
                    _chartBollingerElement.DrawTemplate.VisualTree.SetValue(Shape.FillProperty, new SolidColorBrush(Colors.DeepSkyBlue));

                    area.Elements.Add(_candlesElem);
                    area.Elements.Add(_chartBollingerElement);

                    this.GuiAsync(() => DrawCandles(candles));

                    _candleManager = new CandleManager(_trader);
                    
                    _series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);
                    
                    _series.ProcessCandle += Draw;
                    
                    _candleManager.Start(_series);

                    _chartWindow.Show();
                }
            }
        }

        private void DrawCandles(IEnumerable<Candle> candles)
        {
            foreach (var candle in candles)
                _chartWindow.Chart.ProcessCandle(_candlesElem, candle);
        }

        private void Draw(Candle obj)
        {
            if (obj.State == CandleStates.Finished || obj.State == CandleStates.Changed)
            {
                var final = obj.State == CandleStates.Finished;

                //значения у индикаторов в данный момент времени(finished,changed)

                var val = _chartBollingerElement.Indicator.Process(new DecimalIndicatorValue(obj.ClosePrice) {IsFinal = final});
                var bollingerValue = new ChartIndicatorValue(_chartBollingerElement.Indicator, val);
                //определеяем время последней свечки
                var timeFrame = (TimeSpan)_series.Arg;
                var time = timeFrame.GetCandleBounds(_series.Security).Min - timeFrame;

                //добавляем свечки и график индикаторов на чарт
                if (obj.State == CandleStates.Finished || (obj.State == CandleStates.Changed && obj.OpenTime >= time))
                {
                    this.GuiAsync(() => _chartWindow.Chart.ProcessValues(obj.OpenTime, new Dictionary<IChartElement, object>
                                                                                          {
                                                                                              {_candlesElem, obj},
                                                                                              {_chartBollingerElement, bollingerValue},
                                                                                          }));
                }
            }
        }
    }
}
 
IvanB
IvanB Autor

UsilaDobry: Доброго дня!

Пробую добавить вывод реальных свечей от Альфа-коннектора, появляется ошибка "Параметр свечки 00-10-00 неправильный" в строке _candleManager.Start(series); Причем здесь параметр свечки, если в менеджер свечей передается серия свечей, и почему параметр серии 10 минут неправильный?..

using System;
using System.Collections.Generic;
using System.Windows;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using Ecng.Common;
using Ecng.Collections;
using Ecng.ComponentModel;
using Ecng.Xaml;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Indicators.Trend;
using StockSharp.BusinessEntities;
using StockSharp.AlfaDirect;
using StockSharp.Logging;
using StockSharp.Xaml;
using StockSharp.Xaml.Charting;

namespace MARKET_SUCCESS_ALFA
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        private AlfaTrader _trader;
        private CandleManager _candleManager;
        private CandleSeries _series;
        private bool _isExportStarted;
        private readonly ObservableCollection<Security> _securitiesSource = new ObservableCollection<Security>();
        private readonly ObservableCollection<Portfolio> _portfoliosSource = new ObservableCollection<Portfolio>();

        private readonly LogManager _logManager = new LogManager();
        private readonly MonitorWindow _monitor = new MonitorWindow();

        //окно для отображения графика со свечками
        private ChartWindow _chartWindow;
        private ChartCandleElement _candlesElem;
        private ChartIndicatorElement _chartBollingerElement; 

        public MainWindow()
        {
            InitializeComponent();

            var items = HistoryInterval.Items;
            items.Add(new ComboBoxItem { Content = "1 минута", Tag = AlfaTimeFrames.Minute1 });
            items.Add(new ComboBoxItem { Content = "5 минут", Tag = AlfaTimeFrames.Minute5 });
            items.Add(new ComboBoxItem { Content = "10 минут", Tag = AlfaTimeFrames.Minute10 });
            items.Add(new ComboBoxItem { Content = "15 минут", Tag = AlfaTimeFrames.Minute15 });
            items.Add(new ComboBoxItem { Content = "30 минут", Tag = AlfaTimeFrames.Minute30 });
            items.Add(new ComboBoxItem { Content = "1 час", Tag = AlfaTimeFrames.Hour });
            items.Add(new ComboBoxItem { Content = "День", Tag = AlfaTimeFrames.Day });
            items.Add(new ComboBoxItem { Content = "Неделя", Tag = AlfaTimeFrames.Week });
            items.Add(new ComboBoxItem { Content = "Месяц", Tag = AlfaTimeFrames.Month });
            items.Add(new ComboBoxItem { Content = "Год", Tag = AlfaTimeFrames.Year });

            HistoryInterval.SelectedIndex = 2;
            
            From.Value = DateTime.Today - TimeSpan.FromDays(7);
            To.Value = DateTime.Today;

            Security.ItemsSource = _securitiesSource;
            Portfolio.ItemsSource = _portfoliosSource;

            _logManager.Listeners.Add(new FileLogListener());
            _logManager.Listeners.Add(new GuiLogListener(_monitor));
            _monitor.Show();
        }

        private void ConnectClick(object sender, RoutedEventArgs e)
        {
            // создаем шлюз
            _trader = new AlfaTrader();

            _logManager.Sources.Add(_trader);

            _trader.ProcessDataError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), "Ошибка обработки данных"));
            _trader.NewSecurities += securities =>
            {
                this.GuiAsync(() => _securitiesSource.AddRange(securities));

                // начинаем получать текущие сделки (для построения свечек в реальном времени)
                securities.ForEach(_trader.RegisterTrades);
            };
            _trader.NewPortfolios += portfolios => this.GuiAsync(() => _portfoliosSource.AddRange(portfolios));
            _trader.Connected += () => this.GuiAsync(() =>
            {
                ExportBtn.IsEnabled = true;
                ConnectBtn.IsEnabled = false;
            });

            _trader.Connect();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            if (_trader != null)
            {
                if (_isExportStarted)
                    StopExport();

                _logManager.Sources.Remove(_trader);

                _trader.Dispose();
            }

            base.OnClosing(e);
        }

        private void StartExport()
        {
            _isExportStarted = true;
            _trader.StartExport();
        }

        private void StopExport()
        {
            _trader.StopExport();
            _isExportStarted = false;
        }

        private void ExportClick(object sender, RoutedEventArgs e)
        {
            if (_isExportStarted)
                StopExport();
            else
                StartExport();
        }

        private Security SelectedSecurity
        {
            get { return (Security)Security.SelectedValue; }
        }

        private Portfolio SelectedPortfolio
        {
            get { return (Portfolio)Portfolio.SelectedValue; }
        }

        private void SecuritySelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ShowChart.IsEnabled = SelectedSecurity != null;
        }

        private void PortfolioSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            TradingBtn.IsEnabled = SelectedPortfolio != null;
        }
        private void ShowChartClick(object sender, RoutedEventArgs e)
        {
            var security = SelectedSecurity;

            var timeFrame = (AlfaTimeFrames)((ComboBoxItem)HistoryInterval.SelectedItem).Tag;

            if (From.Value != null)
            {
                var from = From.Value.Value;
                if (To.Value != null)
                {
                    var to = To.Value.Value;

                    if (@from > to)
                    {
                        return;
                    }

                    var candles = _trader.GetHistoryData(security, timeFrame, new Range<DateTime>(@from, to));
                    
                    _chartWindow = new ChartWindow
                    {
                        Title = "{0}, {1}, {2} - {3}".Put(security.Code,
                                                          ((ComboBoxItem)HistoryInterval.SelectedItem).Content,
                                                          @from.ToString(CultureInfo.InvariantCulture), to.ToString(CultureInfo.InvariantCulture))
                    };

                    var area = new ChartArea();
                    _chartWindow.Chart.ChartTheme = "ExpressionDark";
                    _chartWindow.Chart.IsAutoScroll = true;
                    _chartWindow.Chart.Areas.Add(area);

                    _candlesElem = new ChartCandleElement
                    {
                        Antialiasinig = false,
                        UpBodyColor = Colors.Chartreuse,
                        UpWickColor = Colors.Chartreuse,
                        DownBodyColor = Colors.Red,
                        DownWickColor = Colors.Red,
                        IsLegend = true,
                    };

                    _chartBollingerElement = new ChartIndicatorElement
                    {
                        Antialiasinig = false,
                        Color = Colors.DeepSkyBlue,
                        IsLegend = true,
                        Indicator = new BollingerBands
                        {
                            Length = 20,
                            Width = 2
                        },
                        Title = "Bollinger Bands",
                        DrawStyle = ChartIndicatorDrawStyles.Line,
                    };
                    _chartBollingerElement.DrawTemplate.VisualTree.SetValue(Shape.FillProperty, new SolidColorBrush(Colors.DeepSkyBlue));

                    area.Elements.Add(_candlesElem);
                    area.Elements.Add(_chartBollingerElement);

                    this.GuiAsync(() => DrawCandles(candles));

                    _candleManager = new CandleManager(_trader);
                    
                    _series = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);
                    
                    _series.ProcessCandle += Draw;
                    
                    _candleManager.Start(_series);

                    _chartWindow.Show();
                }
            }
        }

        private void DrawCandles(IEnumerable<Candle> candles)
        {
            foreach (var candle in candles)
                _chartWindow.Chart.ProcessCandle(_candlesElem, candle);
        }

        private void Draw(Candle obj)
        {
            if (obj.State == CandleStates.Finished || obj.State == CandleStates.Changed)
            {
                var final = obj.State == CandleStates.Finished;

                //значения у индикаторов в данный момент времени(finished,changed)

                var val = _chartBollingerElement.Indicator.Process(new DecimalIndicatorValue(obj.ClosePrice) {IsFinal = final});
                var bollingerValue = new ChartIndicatorValue(_chartBollingerElement.Indicator, val);
                //определеяем время последней свечки
                var timeFrame = (TimeSpan)_series.Arg;
                var time = timeFrame.GetCandleBounds(_series.Security).Min - timeFrame;

                //добавляем свечки и график индикаторов на чарт
                if (obj.State == CandleStates.Finished || (obj.State == CandleStates.Changed && obj.OpenTime >= time))
                {
                    this.GuiAsync(() => _chartWindow.Chart.ProcessValues(obj.OpenTime, new Dictionary<IChartElement, object>
                                                                                          {
                                                                                              {_candlesElem, obj},
                                                                                              {_chartBollingerElement, bollingerValue},
                                                                                          }));
                }
            }
        }
    }
}
 

Если Вы используете свечи типа TimeFrameCandle, то подобное сообщение говорит о том, что параметр Arg свечи (для типа TimeFrameCandle) имеет тип отличный от TimeSpan.

UsilaDobry
UsilaDobry

Действительно, поменял тип серии свечей, вместо TimeFrameCandle указал AlfaTimeFrames в строке

_series = new CandleSeries(typeof(AlfaTimeFrames), security, timeFrame);

ошибка пропала, но выводятся только исторические свечи, реальные не хотят...

IvanB
IvanB Autor

UsilaDobry: Действительно, поменял тип серии свечей, вместо TimeFrameCandle указал AlfaTimeFrames в строке

_series = new CandleSeries(typeof(AlfaTimeFrames), security, timeFrame);

> 
> ошибка пропала, но выводятся только исторические свечи, реальные не хотят...

Посмотрите пример SampleAlfaCandles и обновите библиотеки S#.
UsilaDobry
UsilaDobry

IvanB: Посмотрите пример SampleAlfaCandles и обновите библиотеки S#.

Я именно этот пример и пытаюсь доработать. В этом примере выводятся только исторические свечи. А я хочу притулить туда candleManager, но почитав ветку форума AlfaDirect понял, что Аlfa не дружит с candleManager. Видимо по этой причине и пример сделан только с историческими свечами. Я работаю сейчас с библиотекой 4.1.13.2, скачал 4.1.14.1, там пример SampleAlfaCandles нисколько не изменился. Кстати, пример из предыдущей библиотеки работает корректно, а сейчас запустил из новой библиотеки, выдает ошибку обработки данных, при этом код идентичный. Не знаю чем это объяснить... Ну да ладно, меня интересуют больше реальные свечи из Alfa. Я взял вот этот блок вывода исторических свечей

private void ShowChartClick(object sender, RoutedEventArgs e)
       {
           
               var security = SelectedSecurity;
               
               var timeFrame = (AlfaTimeFrames)((ComboBoxItem)HistoryInterval.SelectedItem).Tag;
                               
               if (From.Value != null)
               {
                   var from = From.Value.Value;
                   if (To.Value != null)
                   {
                       var to = To.Value.Value;
               
                       if (@from > to)
                       {
                           return;
                       }
               
                       var candles = _trader.GetHistoryData(security, timeFrame, new Range<DateTime>(@from, to));
                       
                       _chartWindow = new ChartWindow
                       {
                           Title = "{0}, {1}, {2} - {3}".Put(security.Code,
                                                             ((ComboBoxItem)HistoryInterval.SelectedItem).Content,
                                                             @from.ToString(CultureInfo.InvariantCulture), to.ToString(CultureInfo.InvariantCulture))
                       };
this.GuiAsync(() => DrawCandles(candles));

И добавил к нему блок обработки реальных свечей через candleManager

_candleManager = new CandleManager(_trader);
                
                        _series = new CandleSeries(typeof(TimeFrameCandle), security, (TimeSpan)AlfaTimeFrames.Minute10);
                        
                        _series.ProcessCandle += Draw;
                        
                        _candleManager.Start(_series);
 private void Draw(Candle candle)
        {
            if (candle.State == CandleStates.Finished || candle.State == CandleStates.Changed)
            {
                var final = candle.State == CandleStates.Finished;
                
                var val = _chartBollingerElement.Indicator.Process(new DecimalIndicatorValue(candle.ClosePrice) {IsFinal = final});
                var bollingerValue = new ChartIndicatorValue(_chartBollingerElement.Indicator, val);
                
                var timeFrame = (TimeSpan)_series.Arg;
                var time = timeFrame.GetCandleBounds(_series.Security).Min - timeFrame;
                
                if (candle.State == CandleStates.Finished || (candle.State == CandleStates.Changed && candle.OpenTime >= time))
                {
                    this.GuiAsync(() => _chartWindow.Chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
                                                                                          {
                                                                                              {_candlesElem, candle},
                                                                                              {_chartBollingerElement, bollingerValue},
                                                                                          }));
                }
            }
        }

Вроде бы все как учили, но появляется ошибка

UsilaDobry
UsilaDobry

Доброго вечера Иван! Может Вы мне подскажете, а то разработчики на форуме заняты более серьезными задачами или мои вопросы слишком глупы...:-) К примеру в Quik мы выводили реальные свечи вот так..., причем реальные свечи получаем с 10-00, а историю можно было получить только за прошлые дни

_candleManager = new CandleManager(ConnectionInterFace.SafeConnection.Trader);
            
            var security = ConnectionInterFace.SelectedSecurity;
            
            _candleSeries = new CandleSeries(typeof(TimeFrameCandle), security, timeFrame);
            
            _candleSeries.ProcessCandle += Draw;

            _candleManager.Start(_candleSeries);

private void Draw(Candle candle)
        {
            //Временные рамки свечи
            var candleBounds = ((TimeSpan) candle.Arg).GetCandleBounds(_candleSeries.Security);
                                    
            //Работаем только с завершенными свечами и одной последней свечей с произвольным состоянием
            if (candle.State == CandleStates.Finished || candle.OpenTime >= candleBounds.Min)
            {
                //Выводим значения на график
                this.GuiAsync(() => Chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
                    {
                        {_chartCandleElement, candle},                  
                    }));
            }
        }

Из терминала AlfaDirect реальные свечи получаются гораздо проще, при этом историю можно получить вплоть до предпоследней завершенной свечки торговой сессии ```csharp _candleManager = new CandleManager(_trader);

            _series = new CandleSeries(typeof(TimeFrameCandle), security, (TimeSpan)AlfaTimeFrames.Minute10);

            _series.ProcessCandle += candle => this.GuiAsync(() => _chartWindow.Chart.ProcessCandle(_candlesElem, candle));

            _candleManager.Start(_series);
Но...если в Quik легко отделить завершенные реальные свечи от последней незавершенной, например убрать условие candle.OpenTime >= candleBounds.Min и на график будут выводится только завершенные реальные свечи, то в AlfaDirect такой прием не катит... Не могу дать ума, как отделить завершенные реальный свечи от последней незавершенной. Банальная проверка на finished не помогает... Всё равно выводятся завершенные свечи и последняя незавершенная...
```csharp
_candleManager = new CandleManager(_trader);
                
                _series = new CandleSeries(typeof(TimeFrameCandle), security, (TimeSpan)AlfaTimeFrames.Minute10);

                _series.ProcessCandle += candle => 
                    {
                        if (candle.State == CandleStates.Finished)
                        {
                          
                          this.GuiAsync(() =>_chartWindow.Chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
                                                                   {
                                                                       {_candlesElem, candle},
                                                                   }));
                                               
                    };
_candleManager.Start(_series);
Самунджян Артем

UsilaDobry: Может Вы мне подскажете.. Разбирательства переносятся в Skype, для более оперативного решения проблемы 😀

Bond
Bond

На картинке в начале урока цвета свечей должны быть в точности наоборот. Или поменяйте местами цены открытия и закрытия свечи.

IvanB
IvanB Autor

Bond: На картинке в начале урока цвета свечей должны быть в точности наоборот. Или поменяйте местамы цены открытия и закрытия свечи.

Благодарим за информацию.

Prival
Prival

Урок №4 если назначить CandlesDownloadUsing запускаемым проектом, то выдается ошибка Ошибка 2 Имя "PendingOrders" отсутствует в текущем контексте ...\StockSharp Lessons\StockSharp.Edu\04_lesson (Candles, Charts, Historical data)\CandlesDownloadUsing\BollingerStrategy.cs 29 79 CandlesDownloadUsing

если строку

return Orders.Count(o => o.State != OrderStates.Done) == 0 && PendingOrders.Count() == 0;

записать вот так return Orders.Count(o => o.State != OrderStates.Done) == 0; // && PendingOrders.Count() == 0;

то запускается.

Причем это единственное что смог запустить в 4-ом уроке. Ни одно решение не запускается. Прикладываю скрин

IvanB
IvanB Autor

Prival: Урок №4 если назначить CandlesDownloadUsing запускаемым проектом, то выдается ошибка Ошибка 2 Имя "PendingOrders" отсутствует в текущем контексте ...\StockSharp Lessons\StockSharp.Edu\04_lesson (Candles, Charts, Historical data)\CandlesDownloadUsing\BollingerStrategy.cs 29 79 CandlesDownloadUsing

если строку

return Orders.Count(o => o.State != OrderStates.Done) == 0 && PendingOrders.Count() == 0;

записать вот так return Orders.Count(o => o.State != OrderStates.Done) == 0; // && PendingOrders.Count() == 0;

то запускается.

Причем это единственное что смог запустить в 4-ом уроке. Ни одно решение не запускается. Прикладываю скрин

Какую версию библиотеки S# используете?

Prival
Prival

Какую версию библиотеки S# используете? немного не понял вопрос. Там же вроде в проект добавлены все библиотеки. Я ничего не добавлял. Запускал какие есть Скажите какие библиотеки (*.dll) мне посмотреть и как у них определить версию ?

IvanB
IvanB Autor

Какую версию библиотеки S# используете? немного не понял вопрос. Там же вроде в проект добавлены все библиотеки. Я ничего не добавлял. Запускал какие есть Скажите какие библиотеки (*.dll) мне посмотреть и как у них определить версию ?

Я имею в виду библиотеки S#, эти библиотеки имеют префикс StockSharp.* , например StockSharp.Algo.dll. Посмотреть версию можно, либо в обозревателе файлов Windows, для этого выбираем пункт Свойства -> Подробно и смотрим поле Версия продукта. Можно посмотреть версию с VS, для этого нужно выбрать интересующую библиотеку в обозревателе проекта (каталог References) и в окне Свойств (Properties) смотрим поле Version.

Prival
Prival

На видео создается проект CandlesChartProject но его нет в исходном коде, там что то другое

IvanB
IvanB Autor

Prival: На видео создается проект CandlesChartProject но его нет в исходном коде, там что то другое

Благодарим за замечание, в ближайший день проект появится в доступе.

Prival
Prival

Все равно что то не то... или я делаю что то не так, прилагаю скрин

если выбираю StockShap.Edu.sln то эти проекты в Обозревателе решений не появляются.

  1. Урок CandlesChartProject появился
  2. Версия StockSharp.Algo 4.1.16.1 версия среды выполнения 4.1.16.1
IvanB
IvanB Autor

Prival: Все равно что то не то... или я делаю что то не так, прилагаю скрин

если выбираю StockShap.Edu.sln то эти проекты в Обозревателе решений не появляются.

  1. Урок CandlesChartProject появился
  2. Версия StockSharp.Algo 4.1.16.1 версия среды выполнения 4.1.16.1

Техническая ошибка, проверьте, теперь проект CandlesChartProject должен быть в уроке 4.

MenDel
MenDel

Всем привет! Столкнулся с проблемой, вылетает ошибка. Сделки выводятся на график, но в любой момент вылетает ошибка.

Код такой же как и в примере. Если убрать эту строчку this.GuiAsync(() => Chart.ProcessCandle(_chartCandleEkement, candle)); то ошибка пропадает, следовательно она возникает при выводе.

И такой нюанс. В примере добавлено using StockSharp.Xaml; А у меня так не работает, пришлось написать using StockSharp.Xaml.Charting; Почему так?


<Window x:Class="TestQuik2014.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:stock="clr-namespace:StockSharp.Xaml.Charting;assembly=StockSharp.Xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="WindowLoaded">
    <Grid>
       
        <Button Content="Candle" Height="23" HorizontalAlignment="Left" Margin="12,213,0,0" Name="button_GetCandles" VerticalAlignment="Top" Width="75" Click="button_GetCandles_Click" Loaded="WindowLoaded" />

        <stock:Chart x:Name="Chart" Margin="104,0,0,0" />
    </Grid>
</Window>
using System;
using Ecng.Collections;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using Ecng.Xaml;
using StockSharp.Algo.Candles;
using StockSharp.BusinessEntities;
using StockSharp.Quik;
using StockSharp.Xaml.Charting;

namespace TestQuik2014
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private QuikTrader _trader;
        private Security MySecurity {get; set;}

      


        private CandleManager _candleManager;
        private CandleSeries _candleSeries;
        private ChartArea _chartArea;
        private ChartCandleElement _chartCandleEkement;

        


        private void button_GetCandles_Click(object sender, RoutedEventArgs e)
        {
            _chartCandleEkement = new ChartCandleElement();
            _chartArea.Elements.Add(_chartCandleEkement);
            RunProcessGetCandles();

        }

        private void RunProcessGetCandles()
        {
            _candleManager = new CandleManager(_trader);
            var timeFrame = TimeSpan.FromMinutes(1);
            _candleSeries = new CandleSeries(typeof (TimeFrameCandle), MySecurity, timeFrame);

            _candleSeries.ProcessCandle += Draw;
            _candleManager.Start(_candleSeries);
            
        }
       
        private void Draw(Candle candle)
        {
            var candleBounce = ((TimeSpan) candle.Arg).GetCandleBounds(_candleSeries.Security);

            if (candle.State == CandleStates.Finished || candle.OpenTime >= candleBounce.Min)
            {            
                this.GuiAsync(() => Chart.ProcessCandle(_chartCandleEkement, candle));
            }
        }

        private void InitChart()
        {
            Chart.IsAutoScroll = true;
            _chartArea = new ChartArea();
            Chart.Areas.Add(_chartArea);

        }

        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            InitChart();            
        }

       
    }
}

И еще вопрос, почему в примере одно окно со свечками, а у меня получилось два, а свечки в нижнем

Николай
Николай

Присоединяюсь к MenDel,

Выдается ошибка (На видео это время 28:50) :

An unhandled exception of type 'System.ArgumentNullException' occurred in StockSharp.Xaml.dll

Ругается на эту строку: ```csharp Chart.ProcessCandle(_chartCandleElement, candle)




P.S. 

При попытке запустить скаченный оригинал, также выдается ошибка: An unhandled exception of type 'System.ArgumentNullException' occurred in mscorlib.dll

И ругается на код: 

```csharp
Chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
                    {
                        {_chartCandleElement, candle},
                        {_chartIndicatorSmaElement, chartValueSma},
                        {_chartIndicatorMyElement, chartValueMy}
                    })
JaguarFX
JaguarFX

Николай: Присоединяюсь к MenDel,

Выдается ошибка (На видео это время 28:50) :

An unhandled exception of type 'System.ArgumentNullException' occurred in StockSharp.Xaml.dll

Ругается на эту строку: Chart.ProcessCandle(_chartCandleElement, candle)

Присоединяюсь к замечанию Mendel и Николая, уже месяц прошел с даты публикации ошибки , но ошибка все равно не исправлена.

У меня VS2012 более подробную информацию об ошибке - проблема в том что, не найдены символы для библиотеки Abt.Controls.SciChart.Wpf.2.2 (см. детали на скрин-шоте).

IvanB
IvanB Autor

lebedevsrg:

Николай: Присоединяюсь к MenDel,

Выдается ошибка (На видео это время 28:50) :

An unhandled exception of type 'System.ArgumentNullException' occurred in StockSharp.Xaml.dll

Ругается на эту строку: Chart.ProcessCandle(_chartCandleElement, candle)

Присоединяюсь к замечанию Mendel и Николая, уже месяц прошел с даты публикации ошибки , но ошибка все равно не исправлена.

У меня VS2012 более подробную информацию об ошибке - проблема в том что, не найдены символы для библиотеки Abt.Controls.SciChart.Wpf.2.2 (см. детали на скрин-шоте). Надо обновить все библиотеки в проекте (либо в каталоге, откуда подключали dll файлы, либо в каталоге Debug, в зависимости от того как подключали) и все будет работать.

JaguarFX
JaguarFX

Николай: Присоединяюсь к MenDel, Надо обновить все библиотеки в проекте (либо в каталоге, откуда подключали dll файлы, либо в каталоге Debug, в зависимости от того как подключали) и все будет работать.

Иван, ошибка периодически вылезает снова и снова - постоянно удалять и перезагружать библиотеки это не дело.

Можно вас попросить выложить в общий доступ файл "Abt.Controls.SciChart.Wpf.2.2.pdb" который VisualStudio запрашивает при появлении этой ошибки?

IvanB
IvanB Autor

Все должно работать: http://gyazo.com/3702a3a815cdf7cef566ad0f27113aed

Попробуйте следующее: в контекстном меню (прав кнопкой мыши) каталога StockSharp.Edu на tfs выбираем Advanced -> Get Specific Version... и там как на скриншоте, затем Get. http://gyazo.com/ed9dcb73299268e01a446292db534aec

Таким образом мы загрузим последнюю версию файлов с сервера.

Николай
Николай

Иван, спасибо за комментарий.

Начал разбираться в своей ошибке, и обнаружил следующее:

        private void GetCandlesClick(object sender, RoutedEventArgs e)
        {
            _chartCandleElement = new ChartCandleElement();
            _chartArea.Elements.Add(_chartCandleElement);
            RunProcessGetCandles();
        }

Это так как должно быть, однако в видео был пропущен момент написания кода:

       
            _chartCandleElement = new ChartCandleElement();
            _chartArea.Elements.Add(_chartCandleElement);         

Т.е. те кто будет писать по уроку код получит следующее:

        private void GetCandlesClick(object sender, RoutedEventArgs e)
        {
                       RunProcessGetCandles();
        }

Возможно это нужно будет пометить в тексте самого урока для пользователей.

Также хотел задать вопрос по коду ConnectionInterFace.Main Можешь скинуть код функции Main, т.к. ты ее применяешь в уроках, для отсоединения, однако в References StockSharp.WpfConnectionInterface не могу найти.

IvanB
IvanB Autor

Спасибо за замечание. Свойство Main в ConnectionInterFace нам не нужно более, т.к. мы сделали следующее:


        /// <summary>
        /// Событие завершения загрузки данного контрола
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="routedEventArgs"></param>
        void InterFace_Loaded(object sender, RoutedEventArgs routedEventArgs)
        {
            //Получить родительское окно
            var window = Window.GetWindow(Parent);
            if (window != null)
                window.Closed += delegate
                    {
                        if (_safeConnection != null)
                            _safeConnection.DisConnectSafe();
                    };
        }

Тем самым избавились от необходимости идентификации дополнительного свойства.

Maxim
Maxim

Здравствуйте. Не отображается последняя свеча текущего дня и ее изменения (подключение через TransaqConnector). Я использую StockSharp API 4.2.1.7. Подскажите, пожалуйста, что делать...

Код:

 
private void RunProcessGetCandles()
        {
            _candleManager = new CandleManager(interFace.SafeConnection.Trader);
            var security = interFace.SelectedSecurity;
            var timeFrame = TimeSpan.FromMinutes(5);
            _candleSeries = new CandleSeries(typeof (TimeFrameCandle), security, timeFrame);
            _candleSeries.ProcessCandle += Draw;
            _candleManager.Start(_candleSeries);
        }

        private void Draw(Candle candle)
        {
            var candleBounds = ((TimeSpan) candle.Arg).GetCandleBounds(_candleSeries.Security);
            if (candle.State == CandleStates.Finished || candle.OpenTime >= candleBounds.Min)
            {
                this.GuiAsync(() => Chart.ProcessCandle(_chartCandleElement, candle));
            }
            
        }

        private void InitChart()
        {
            Chart.IsAutoScroll = true; 
            _chartArea = new ChartArea();
            Chart.Areas.Add(_chartArea);
            _chartCandleElement = new ChartCandleElement();
            _chartArea.Elements.Add(_chartCandleElement);
        }

        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            InitChart();
        }

IvanB
IvanB Autor

Попробуйте обновить время через интернет на вашем компьютере

Maxim
Maxim

IvanB: Попробуйте обновить время через интернет на вашем компьютере

Не помогло. Пробовал также время на пару минут раньше устанавливать. Черная стрелка с ценой последней сделки вообще отсутствует в области графика.

IvanB
IvanB Autor

Maxim:

IvanB: Попробуйте обновить время через интернет на вашем компьютере

Не помогло. Пробовал также время на пару минут раньше устанавливать. Черная стрелка с ценой последней сделки вообще отсутствует в области графика.

Тогда попробуйте сделать так:


        private void Draw(Candle candle)
        {
            this.GuiAsync(() => Chart.ProcessCandle(_chartCandleElement, candle)); 
        }

код выводит абсолютно все свечи, если заработает, то проблема с расхождением времени приходящих свечей и вашего ПК.

Maxim
Maxim

Тогда попробуйте сделать так: Код:

    private void Draw(Candle candle)
    {
        this.GuiAsync(() => Chart.ProcessCandle(_chartCandleElement, candle));
    }

код выводит абсолютно все свечи, если заработает, то проблема с расхождением времени приходящих свечей и вашего ПК.

То же самое...Не отображается

Maxim
Maxim

В проекте Transaq > Sample тоже не выводится текущая свеча. А вот в проекте Quik > SampleCandles все Ok!

IvanB
IvanB Autor

Maxim: В проекте Transaq > Sample тоже не выводится текущая свеча. А вот в проекте Quik > SampleCandles все Ok!

Попробуйте так:


_candleManager.Processing += Draw;

при этом заголовок метода Draw нужно изменить:


private void Draw(CandleSeries series, Candle candle)

Maxim
Maxim

IvanB:

Maxim: В проекте Transaq > Sample тоже не выводится текущая свеча. А вот в проекте Quik > SampleCandles все Ok!

Попробуйте так:

_candleManager.Processing += Draw;

> при этом заголовок метода Draw нужно изменить:
> ```csharp

private void Draw(CandleSeries series, Candle candle)

Один и тот же код нормально работает при подключении через QuikTrader, a при подключении через TransaqTrader не отображает текущую (последнюю) свечу. Видео подключения по ссылке: http://youtu.be/4OH39uUWuRo

Maxim
Maxim

Могу, если надо, видео с экрана куда-нибудь выложить...

JaguarFX
JaguarFX

Судя по всему в библиотеке StockSharp.Xaml версии 4.1.2.7 уже нет компонента SciChart, о котором рассказывается в видео-уроке. Прошу подсказать какой компонент теперь его заменил, и внести эту информацию в раздел "Изменения в проектах".

Разобрался: необходимо подключать библиотеку StockSharp.Xaml.Charting и использовать элемент Chart.

Maxim
Maxim

Попробуйте так: Код:

_candleManager.Processing += Draw;

при этом заголовок метода Draw нужно изменить: Код:

private void Draw(CandleSeries series, Candle candle)

Один и тот же код нормально работает при подключении через QuikTrader, a при подключении через TransaqTrader не отображает текущую (последнюю) свечу . Возможно, Вы меня не до конца поняли, но график при подключении через Quik изначально нормально выводился, а через Transaq - проблема какая была, такая и осталась... Я какое-то время планирую пользоваться транзаком, поэтому хотелось бы понять, в чем дело.

Maxim
Maxim

Автор: IvanB Перейти к цитате

Автор: Maxim Перейти к цитате В проекте Transaq > Sample тоже не выводится текущая свеча. А вот в проекте Quik > SampleCandles все Ok!

Попробуйте так: Код:

_candleManager.Processing += Draw;

при этом заголовок метода Draw нужно изменить: Код:

private void Draw(CandleSeries series, Candle candle)

Один и тот же код нормально работает при подключении через QuikTrader, a при подключении через TransaqTrader не отображает текущую (последнюю) свечу. Видео подключения по ссылке:

Может, дело в этом: "Для получения обновлений по выбранному инструменту и тиков необходимо воспользоваться методами RegisterSecurity(Security) и RegisterTrades(Security) соответственно" (п. 6 Примеры работы с Transaq документации по StockSharp)???

Я попробовал добавить методы RegisterSecurity и RegisterTrades в тело метода RunProcessGetCandles() - результат тот же, последней свечи нет!(

IvanB
IvanB Autor

Автор: IvanB Перейти к цитате

Автор: Maxim Перейти к цитате В проекте Transaq > Sample тоже не выводится текущая свеча. А вот в проекте Quik > SampleCandles все Ok!

Попробуйте так: Код:

_candleManager.Processing += Draw;

при этом заголовок метода Draw нужно изменить: Код:

private void Draw(CandleSeries series, Candle candle)

Один и тот же код нормально работает при подключении через QuikTrader, a при подключении через TransaqTrader не отображает текущую (последнюю) свечу. Видео подключения по ссылке:

Может, дело в этом: "Для получения обновлений по выбранному инструменту и тиков необходимо воспользоваться методами RegisterSecurity(Security) и RegisterTrades(Security) соответственно" (п. 6 Примеры работы с Transaq документации по StockSharp)???

Я попробовал добавить методы RegisterSecurity и RegisterTrades в тело метода RunProcessGetCandles() - результат тот же, последней свечи нет!(

Возможно баг в коннекторе Transaq, будем разбираться...

Maxim
Maxim

IvanB: [ Возможно баг в коннекторе Transaq, будем разбираться...

Понял, спасибо! А как можно будет узнать, когда исправите? или теперь придется ждать релиза новой версии StockSharp API?

IvanB
IvanB Autor

Maxim:

IvanB: [ Возможно баг в коннекторе Transaq, будем разбираться...

Понял, спасибо! А как можно будет узнать, когда исправите? или теперь придется ждать релиза новой версии StockSharp API?

Всего скорее ждать новой версии

Maxim
Maxim

IvanB: Возможно баг в коннекторе Transaq, будем разбираться...

Еще по поводу транзака: у меня не получилось воспользоваться свойством ServerTimeDiff (всегда возвращается null), насколько я понял из документации, это разница времени сервера транзак и времени системы.


 if (Trader1.ConnectionState == ConnectionStates.Connected)
            {
                var servTimeDiff = Trader1.ServerTimeDiff;

                TbServerTimeDiff.Text = servTimeDiff.ToString();
                if (servTimeDiff == null)
                {
                    TbServerTimeDiff.Text = "разница ноль!";
                }

            }