← Назад

Объединение свечей из разных источников

Как можно объединить в одном токине СandleManager свечи из разных источников? Пытаюсь объединить исторические свечи со свечами из шлюза таким образом


            this._cm = new CandleManager(this._trader);

            // хранилище, через которое будет производиться доступ к тиковой и котировочной базе
            this.storage = new TradingStorage(new InMemoryStorage()){ BasePath = "Sec" };

            var builder = new CandleBuilder(new TradeStorageCandleBuilderSource(storage));
            this._cm.Sources.Add(builder);

            // Регистрируем свечи
            var candleToken = this._cm.RegisterTimeFrameCandles(security, this._timeFrame);

В итоге приходят только свечи из шлюза. Если добавить


builder.RegisterTimeFrameCandles(security, _timeFrame);

то в CandleManager придут все свечи и история и трейдер, но это будет два разных токена.

Комментарии (25)

Вход или Создать аккаунт, Войдите или зарегистрируйтесь, чтобы оставить комментарий

Mikhail Sukhov
Mikhail Sukhov

pehas: Если добавить

builder.RegisterTimeFrameCandles(security, _timeFrame);

> то в CandleManager придут все свечи и история и трейдер, но это будет два разных токена.

Вызывать только второй?
pehas
pehas Автор

Mikhail Sukhov: Вызывать только второй? Дело в том, что это нужно для корретной обработки индикатора на исторических данных. А он определяется через IndicatorManager, который принимает конкретный токен.


this.ATRToken = indicatorManager.RegisterIndicator(new AverageTrueRange { Length = 20 }, new CandleTokenIndicatorSource(candleToken, BaseCandleIndicatorSource.ByClose));

Соответственно, если я буду брать только последний токен, индикатор не обработает свечи первого токена.

Mikhail Sukhov
Mikhail Sukhov

А зачем два токена?

pehas
pehas Автор

Mikhail Sukhov: А зачем два токена? В этом как раз и фишка, что мне нужен только один, но я не знаю, как в него засунуть нужные мне свечи 🤨 У меня в гидре хранятся свечи за вчера. Я сегодня утром включаю квик и хочу чтобы индикаторы обработали вчерашние свечи взяв их из гидры и те, что уже успели появиться сегодня в квике. Как получить все эти свечи в одном Токине, чтоб потом использовать в IndicatorManager?

freelancer
freelancer

Я сделал так: воспользовался экспортом произвольных таблиц из примеров. Но ! Новые свечки в той таблице у меня появляются с задержкой в 2 секунды. Поэтому оттуда не беру сегодняшние свечи, а беру их их по таблице всех сделок. А внутри стратегии просто складываю их в одну коллекцию и всё. Всё проходит очень быстро

pehas
pehas Автор

freelancer: Я сделал так: воспользовался экспортом произвольных таблиц из примеров. Но ! Новые свечки в той таблице у меня появляются с задержкой в 2 секунды. Поэтому оттуда не беру сегодняшние свечи, а беру их их по таблице всех сделок. А внутри стратегии просто складываю их в одну коллекцию и всё. Всё проходит очень быстро

Получается, что вы не работаете с индикаторами, по крайней мере не через IndicatorManager, верно? У меня все заточено под CandleManager. C него берут значения все индикаторы и в стратегии стоят правила на приход и обновление свечей по CandleManager. Поэтому просто использовать отдельную коллекцию не получится. А вот если ее положить каким-то образом в CandleManager, то возможно. Но, например, вот так невыходит


CM.Container.AddCandles(candleToken, this.historyCandles);

События CandlesChanged, CandlesStarted для historyCandles (полученных из квика) не вызываются..

freelancer
freelancer

Ну да. IndicatorManager у меня нет. В OnStarting: соединяю свечи, потом:

foreach (Candle c in _candles) Индикатор.Process(new StockSharp.Algo.Indicators.CandleIndicatorValue(c));

А в CandlesFinished прибавляю пришедшую свечу и еще раз Индикатор.Process(new StockSharp.Algo.Indicators.CandleIndicatorValue(пришедшая_свеча));

Как-то так

pehas
pehas Автор

freelancer, cпасибо Поидее, даже учитывая, что CandleManager будет содержать один набор свечек (только из трейдера), можно будет попробовать скормить исторические свечи квика индикаторам через process() Правда, все же странно, что нельзя в S# объединить две группировки свечек..

russ
russ

pehas: freelancer, cпасибо Поидее, даже учитывая, что CandleManager будет содержать один набор свечек (только из трейдера), можно будет попробовать скормить исторические свечи квика индикаторам через process() Правда, все же странно, что нельзя в S# объединить две группировки свечек.. Кстати действительно очень интересный и не понятный момент. Допустим берем свечи из примера на QPILE как экспорт произвольных таблиц, там есть свечи за предыдущие и частично сегоднешний день, допустим робота запускаем в 12 часов. Теперь регистрируем токен: _tokenWorkingTF = _candleManager.RegisterTimeFrameCandles(_security, TimeSpan.FromMinutes(30)); сразу получаем несколько 30 минуток т.к. сессия уже идет, сразу вопрос всегда ли будут получаться только свечи сегодняшнего дня или нет?

Потом загружаем свечи из экспорта произвольных таблиц List<Candle> candles = new List<Candle>(); foreach (QuikCandleFutDay qk in lst) { TimeFrameCandle cndl = new TimeFrameCandle { OpenPrice = qk.OpenPrice, HighPrice = qk.HighPrice, LowPrice = qk.LowPrice, ClosePrice = qk.ClosePrice, TimeFrame = (TimeSpan)token.Arg, Time = DateTime.ParseExact(qk.DateTime.Date + qk.DateTime.Time, "yyyyMMddHHmmss", CultureInfo.InvariantCulture), TotalVolume = qk.Volume, Security = token.Security, }; candles.Add(cndl); } _candleManager.Container.AddCandles(token, candles);

Соответственно в _candleManager будет полный бардак, сначала будут идти свечи части сегодняшнего дня, а потом будут идти свечи из экспорта. Казалось бы можно сначала запихнуть свечи из экспорта, но это невозможно, т.к. нужно создать токен, а как только создается токен в него сразу загоняются свечи сегодняшнего дня. Как решить эту проблему? Т.е. хотелось бы в _candleManager всунуть сначала свечи истории, а потом чтобы туда поступали свечи сегодняшнего дня.

Mikhail Sukhov
Mikhail Sukhov

russ: Как решить эту проблему? Т.е. хотелось бы в _candleManager всунуть сначала свечи истории, а потом чтобы туда поступали свечи сегодняшнего дня.

См. 4.1 из дев ветки. Все сильно поменялось в плане свечек.

russ
russ

Mikhail Sukhov:

russ: Как решить эту проблему? Т.е. хотелось бы в _candleManager всунуть сначала свечи истории, а потом чтобы туда поступали свечи сегодняшнего дня.

См. 4.1 из дев ветки. Все сильно поменялось в плане свечек. Имеется ввиду бета11 версия отсюда? http://stocksharp.codeplex.com/SourceControl/changeset/changes/14551

Alexander
Alexander

russ:

Mikhail Sukhov:

russ: Как решить эту проблему? Т.е. хотелось бы в _candleManager всунуть сначала свечи истории, а потом чтобы туда поступали свечи сегодняшнего дня.

См. 4.1 из дев ветки. Все сильно поменялось в плане свечек. Имеется ввиду бета11 версия отсюда? http://stocksharp.codeplex.com/SourceControl/changeset/changes/14551

да

russ
russ

Alexander Mukhanchikov:

russ:

Mikhail Sukhov:

russ: Как решить эту проблему? Т.е. хотелось бы в _candleManager всунуть сначала свечи истории, а потом чтобы туда поступали свечи сегодняшнего дня.

См. 4.1 из дев ветки. Все сильно поменялось в плане свечек. Имеется ввиду бета11 версия отсюда? http://stocksharp.codeplex.com/SourceControl/changeset/changes/14551

да Прикольно, я так понял CandleToken канул в лету и ему на смену пришел CandleSeries. Буду ждать релиза 4.1. Спасибо, что развиваете библиотеку.

JackSparrow
JackSparrow

Mikhail Sukhov:

russ: Как решить эту проблему? Т.е. хотелось бы в _candleManager всунуть сначала свечи истории, а потом чтобы туда поступали свечи сегодняшнего дня.

См. 4.1 из дев ветки. Все сильно поменялось в плане свечек. А на что конкретно там смотреть, подскажите плиз. Как все свечи в один ряд собирать средствами S#? А то костылики нехочется придумывать.

freelancer
freelancer

Заведите отдельную коллекцию для всех свечей

russ
russ

freelancer: Заведите отдельную коллекцию для всех свечей Что значит заводить отдельную коллекцию? В виде List<Candle> что-ли? Хотелось бы все свечи иметь в candlemanager, чтобы ими пользоваться оттуда.

Moadip
Moadip

Поддерживаю.

Вопрос к разработчикам.

Во многих постах на форуме предлагаете переходить на 4.1 Но если нет справки то как изучать новую функциональность?

Пользоваться objectBrowser не совсем удобно. Или методом научного тыка на основе примеров? Может есть какой то прототип справки? Или если на codeplex в dev ветке, в файлах справки есть что почитать, то как эту справку собрать?

Alexander
Alexander

Справки нет только для свечек. Всё остальное не менялось.

Если используете свечки - то вкратце - CandleToken поменялся на CandleSeries

JackSparrow
JackSparrow

Alexander Mukhanchikov: Справки нет только для свечек. Всё остальное не менялось.

Если используете свечки - то вкратце - CandleToken поменялся на CandleSeries

Спасибо вкратце, сделал свой контейнер, сделал свой график, нарисовал. Но хотелось использовать имеющиеся механизмы. Нет так нет.

Alexander
Alexander

JackSparrow: Нет так нет.

вы о чём?

JackSparrow
JackSparrow

Alexander Mukhanchikov:

JackSparrow: Нет так нет.

вы о чём? Александр я где то на Вашем форуме читал, что если написать индикатор то можно получить несколько ответов. На данный момент я не получил не одного ответа не на один вопрос, хотя я не задаю заумных вопросов, все очень просты, и их не много. Желание спрашивать пропадает. К тому же Вы высказываете сожаления что Вам мало помогают, но время запрачиваемое на разгребание простых вопросов в отсутствие либо доков либо исходников, не оставляет шансов помощ в написании чего либо.

Mikhail Sukhov
Mikhail Sukhov

JackSparrow: Александр я где то на Вашем форуме читал, что если написать индикатор то можно получить несколько ответов.

И я отвечал на ваши вопросы. В основном по Гидре. Поверьте, если бы не помощь по индикаторам, ответом было бы меньше, так как мы отвечаем только на вопросы, касающиеся багов.

JackSparrow: но время запрачиваемое на разгребание простых вопросов в отсутствие либо доков либо исходников, не оставляет шансов помощ в написании чего либо.

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

Если есть претензии по текущей доке, то надо их высказывать сейчас. Будем смотреть, исправлять. До этого вы ничего не писали про качество документации. Значит все было окей. Сейчас что-то изменилось?

Moadip
Moadip

Разбираюсь с 4.1 столкнулся с проблемой.

В 4.0


	    CandleManager _candleManager;
	    readonly TimeSpan _timeFrame = TimeSpan.FromMinutes(5);

        // Начальная и конечная дата для подгрузки истории
	    readonly DateTime _startTime = DateTime.Today - TimeSpan.FromDays(2);
	    readonly DateTime _stopTime = DateTime.Today;

        // Путь к данным истории
	    private const string _historyPath = "e:\\DataServer\\";

            ...

            _candleManager = new CandleManager();
            _candleManager.CandlesStarted += (token, candles) => DrawCandles(candles);
            _candleManager.CandlesChanged += (token, candles) => DrawCandles(candles);

            ...

		private void btnDrawCandleHistory_Click(object sender, RoutedEventArgs e)
		{
            var storage = new TradingStorage(new InMemoryStorage()) { BasePath = _historyPath };

            var builder = new CandleBuilder(new TradeStorageCandleBuilderSource(storage) { From = _startTime, To = _stopTime });
            _candleManager.Sources.Add(builder);

            _candleManager.RegisterTimeFrameCandles(_instr1, _timeFrame);
		}

        private void bntDrawCandleReal_Click(object sender, RoutedEventArgs e)
        {
            _candleManager.Sources.Add(new CandleBuilder(new TradeCandleBuilderSource(_trader)));
            _candleManager.RegisterTimeFrameCandles(_instr1, _timeFrame);
        }

Два метода, один рисует свечки за сегодняшний день, другой - на основе истории.

Делаю по аналогии в 4.1


	    CandleManager _candleManager;
	    readonly TimeSpan _timeFrame = TimeSpan.FromMinutes(5);

        // Начальная и конечная дата для подгрузки истории
	    readonly DateTime _startTime = DateTime.Today - TimeSpan.FromDays(2);
	    readonly DateTime _stopTime = DateTime.Today;

        // Путь к данным истории
	    private const string _historyPath = "e:\\DataServer\\";

            ...

            _candleManager = new CandleManager();
            _candleManager.Processing += DrawCandles;

            ...

        private void btnDrawCandleHistory_Click(object sender, RoutedEventArgs e)
        {
            var storage = new TradingStorage(new InMemoryStorage());

            var cbs = new TradeStorageCandleBuilderSource() { BasePath = _historyPath, Storage = storage };
            var cb = new TimeFrameCandleBuilder();

            cb.Sources.Add(cbs);
            _candleManager.Sources.Add(cb);

            var series = new CandleSeries(typeof(TimeFrameCandle), _instr1, _timeFrame);
            _candleManager.Start(series, _startTime, _stopTime);
        }

        private void bntDrawCandleReal_Click(object sender, RoutedEventArgs e)
        {
            var cbs = new TradeCandleBuilderSource(_trader);
            var cb = new TimeFrameCandleBuilder();

            cb.Sources.Add(cbs);
            _candleManager.Sources.Add(cb);

            var series = new CandleSeries(typeof (TimeFrameCandle), _instr1, _timeFrame);
            _candleManager.Start(series);
        }

За текущий день отрисовывает, историю - нет. Данные от 4.0 переконвертировал в 4.1. Проверил в тесте на истории - нормально.

Что делаю не так? В чем причина?

Moadip
Moadip

За текущий день отрисовывает, историю - нет. Данные от 4.0 переконвертировал в 4.1. Проверил в тесте на истории - нормально.

Что делаю не так? В чем причина?

Отвечу сам на свой вопрос. Для того чтобы отрисовались свечки, надо немного подождать.🙂

Время отрисовки свечек по RI за один день: В 4.0 10 сек. В 4.1 90 сек.

Также в 4.1 наблюдается странный глюк. Допустим есть данные за неделю 26-30 марта. Если выставить дату по которой нет данных, например 25 марта, то будет ошибка - очередь пуста, все правильно. Если выставить дату 30 марта, т.е. последний день существующих данных, то ошибки не будет, но и свечки по какой то причине не генерируются. Если выставить 29 марта, все нормально отрисуется.

Проверял данные в тесте на истории за этот же день(30 марта), все нормально.

В 4.0 такого не наблюдается.

Moadip
Moadip

Подгрузили историю, проверили кол-во значений/свечек в IndicatorManager.Container и CandleManager.Container Подгрузили сегодняшний день, проверили кол-во значений/свечек в IndicatorManager.Container и CandleManager.Container

При остановке series и смене построителя свечек, а затем повторном запуске этой же series свечки в СandleManager.Container за прошлый день не сохраняются. В IndicatorManager.Container прошлые значения сохраняются. Может сделать чтобы также было в СandleManager.Container?

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

Весь код, может кому пригодится.🙂


using System;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using System.ComponentModel;
using MessageBox = System.Windows.MessageBox;

using StockSharp.Algo.Candles.Compression;
using StockSharp.Algo.Indicators.Trend;
using StockSharp.Algo.Storages;

using Ecng.Serialization;
using Ecng.Collections;
using Ecng.Common;
using Ecng.Xaml;

using StockSharp.Quik;
using StockSharp.Algo.Candles;
using StockSharp.BusinessEntities;
using StockSharp.Algo.Indicators;

namespace SimpleCandle
{
    public partial class MainWindow
    {
        QuikTrader _trader;

        Security _instr1;
        private const string _secCode1 = "RIM2";

        CandleManager _candleManager;
        readonly TimeSpan _timeFrame = TimeSpan.FromMinutes(5);

        // Начальная и конечная дата для подгрузки истории
        readonly DateTime _startTime = new DateTime(2012, 4, 3);
        readonly DateTime _stopTime = new DateTime(2012, 4, 4);

        // Путь к данным истории
        private const string _historyPath = @"e:\DataServer4.1\";

        public MainWindow()
        {
            InitializeComponent();

            Path.Text = @"e:\Program Files\QUIK\";
            
        }

        private void FindPath_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new FolderBrowserDialog();

            if (!Path.Text.IsEmpty()) dlg.SelectedPath = Path.Text;
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) Path.Text = dlg.SelectedPath;
        }

        bool _isConnected;

        private void btnConnect_Click(object sender, RoutedEventArgs e)
        {
            if (!_isConnected)
            {
                if (Path.Text.IsEmpty()) MessageBox.Show(this, "Путь к Quik не выбран");
                else
                {
                    if (_trader == null)
                    {
                        _trader = new QuikTrader(Path.Text);

                        _trader.MarketTimeOffset = TimeSpan.FromHours(-3);

                        _isConnected = true;

                        _trader.ConnectionError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString()));
                        _trader.Connected += () => this.GuiAsync(() => btnExportDde.IsEnabled = true);
                        btnExportDde.IsEnabled = true;

                        _trader.NewSecurities += securities => { if (_instr1 == null)_instr1 = securities.FirstOrDefault(sec => sec.Code == _secCode1); };

                        _candleManager = new CandleManager();
                    }

                    _trader.Connect();

                    _isConnected = true;
                    btnConnect.Content = "Отключиться";
                }
            }
            else
            {
                _trader.Disconnect();

                _isConnected = false;
                btnConnect.Content = "Подключиться";
            }
        }

        private readonly SimpleMovingAverage _longSma = new SimpleMovingAverage { Length = 20 };
        
        private CandleSeries _series;
        private TimeFrameCandleBuilder _builder;

        private IndicatorManager _indicatorManager = new IndicatorManager();
        private IndicatorToken _token;
        

        private void btnDrawCandleHistory_Click(object sender, RoutedEventArgs e)
        {
            var storage = new TradingStorage(new InMemoryStorage());
            var cbs = new TradeStorageCandleBuilderSource { BasePath = _historyPath, Storage = storage };
            
            _builder = new TimeFrameCandleBuilder();
            _builder.Sources.Add(cbs);

            _candleManager.Sources.Add(_builder);

            _series = new CandleSeries(typeof(TimeFrameCandle), _instr1, _timeFrame);

            _token = _indicatorManager.RegisterIndicator(_longSma, new CandleSeriesIndicatorSource(_series, candle => candle.ClosePrice));
            _candleManager.Stopped += _candleManager_Stopped;
            
            _candleManager.Start(_series, _startTime, _stopTime);
        }


        private void _candleManager_Stopped(CandleSeries series)
        {
            this.GuiAsync(() => Chart.Candles.AddRange(series.GetCandles()));
        }

        private void bntDrawCandleReal_Click(object sender, RoutedEventArgs e)
        {
            _candleManager.Stopped -= _candleManager_Stopped;
            _candleManager.Stop(_series);

            _candleManager.Sources.Remove(_builder);

            var cbs = new TradeCandleBuilderSource(_trader);
            var cb = new TimeFrameCandleBuilder();

            cb.Sources.Add(cbs);
            _candleManager.Sources.Add(cb);

            _candleManager.Processing += DrawCandles;

            _trader.StartExport(new[] { _trader.TradesTable });

            _candleManager.Start(_series);
        }


        private void DrawCandles(CandleSeries series, Candle candle)
        {
            var bounds = _timeFrame.GetCandleBounds(_trader);

            if (bounds.Min > candle.OpenTime)
            {
                if (candle.State == CandleStates.Finished)
                {
                    this.GuiAsync(() => Chart.Candles.Add(candle));
                }
            }
            else
            {
                this.GuiAsync(() => Chart.Candles.Add(candle));
            }
        }


        private void button1_Click(object sender, RoutedEventArgs e)
        {
            button1.Content = _indicatorManager.Container.GetValues(_token).Count();
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            button2.Content = _candleManager.Container.GetCandles(_series).Count();
        }


        private void btnExportDde_Click(object sender, RoutedEventArgs e)
        {
            if (_isDdeStarted) StopDde();
            else StartDde();
        }

        bool _isDdeStarted;

        private void StartDde()
        {
            _trader.StartExport(new[] { _trader.SecuritiesTable });
            _isDdeStarted = true;
        }

        private void StopDde()
        {
            _trader.StopExport(new[] { _trader.TradesTable, _trader.SecuritiesTable });
            _isDdeStarted = false;
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (_trader != null)
            {
                if (_isDdeStarted) StopDde();
                _trader.Dispose();
            }
        }
    }

}


<Window x:Class="SimpleCandle.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:EcngTradingXaml="clr-namespace:StockSharp.Xaml;assembly=StockSharp.Xaml" Title="" Height="675" Width="763" Closing="Window_Closing" Topmost="False" WindowStartupLocation="CenterScreen">
    
    <Grid>
        <EcngTradingXaml:CandleChart x:Name="Chart" x:FieldModifier="public" Margin="0,70,0,0" HorizontalAlignment="Left" Width="732" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="Path" VerticalAlignment="Top" Width="277" />
        <Button Content="..." Height="23" HorizontalAlignment="Left" Margin="295,12,0,0" Name="FindPath" VerticalAlignment="Top" Width="23" Click="FindPath_Click" />
        <Button Content="Подключиться" Height="23" HorizontalAlignment="Left" Margin="12,41,0,0" Name="btnConnect" VerticalAlignment="Top" Width="98" Click="btnConnect_Click" />
        <Button Content="Экспорт DDE" Height="23" HorizontalAlignment="Left" Margin="116,41,0,0" Name="btnExportDde" VerticalAlignment="Top" Width="98" Click="btnExportDde_Click" IsEnabled="False" />
        <Button Content="Свечки Реал" Height="23" HorizontalAlignment="Left" Margin="324,41,0,0" Name="btnDrawCandleReal" VerticalAlignment="Top" Width="98" Click="bntDrawCandleReal_Click" />
        <Button Content="Свечки История" Height="23" HorizontalAlignment="Left" Margin="220,41,0,0" Name="btnDrawCandlHistory" VerticalAlignment="Top" Width="98" Click="btnDrawCandleHistory_Click"/>
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="463,41,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="544,41,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />
    </Grid>
</Window>

JackSparrow Johny Cash