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


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

[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);
        }


Теги:


Спасибо:


1 2 3  > >>
UsilaDobry

Фотография
Дата: 01.05.2013
Ответить


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

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

Фотография
Дата: 21.05.2013
Ответить


Что-то я не пойму, как мне коллекцию свечей из метода 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

Фотография
Дата: 21.05.2013
Ответить


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

Фотография
Дата: 23.05.2013
Ответить


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);

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

Спасибо:

UsilaDobry

Фотография
Дата: 24.05.2013
Ответить


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

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

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

GetHistoryCandles().ForEach(ProcessCandle);

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

Спасибо:

IvanB

Фотография
Дата: 24.05.2013
Ответить


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

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

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

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

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

Спасибо: UsilaDobry

pft_man

Фотография
Дата: 25.05.2013
Ответить


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

Спасибо:

UsilaDobry

Фотография
Дата: 26.05.2013
Ответить


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

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

Спасибо:

pft_man

Фотография
Дата: 26.05.2013
Ответить


Спасибо.

Спасибо:

pft_man

Фотография
Дата: 27.05.2013
Ответить


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

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

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

Спасибо:
1 2 3  > >>

Добавить файлы через драг-н-дроп, , или вставить из буфера обмена.

loading
clippy