Урок 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 4  > >>
IvanB

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


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

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

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

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

Спасибо:

pft_man

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


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

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

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

Спасибо:

IvanB

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


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

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

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

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

UsilaDobry

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


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

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;
        }
Спасибо:

UsilaDobry

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


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

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

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

Спасибо:

IvanB

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


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

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

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

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

IvanB

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


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

Спасибо: VassilSanych UsilaDobry

UsilaDobry

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


Доброго дня!

Пробую добавить вывод реальных свечей от Альфа-коннектора, появляется ошибка "Параметр свечки 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

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


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

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


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

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

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

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

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

loading
clippy