Обновление инструментов через SmartCOM

Обновление инструментов через SmartCOM
Atom
19.10.2011
Marco


Столкнулся с тем, что Hydra не обновляет список инструментов из Smart'а. При попытке обновления программа надолго задумывается, после чего выводит сообщение "Добавлено 0 инструментов". Hydra версии 4.0.3.

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

Исправления вносились в классы StockSharp.Hydra.Core.MarketDataTrader и StockSharp.Hydra.Core.MarketDataTrader.SecurityUpdate.

Суть изменений:
- Метод MarketDataTrader.Start() ожидал получения данных об инструментах, но экспорт инструментов не запрашивался. Была добавлена обработка информации о портфелях и вызов RegisterPortfolio для каждого полученного портфеля.
- Экземпляр класса SecurityUpdate создавался после вызова Trader.Connect(). Теоретически SecurityUpdate мог опоздать с подключением к событию NewSecurities. Создание SecurityUpdate было перенесено до вызова Trader.Connect().
- События NewPortfolio/NewSecurities не вызывались до завершения SecurityUpdate.Run(), несмотря на наличие вызова Sleep() в теле этого метода. Метод Run() переписан с использованием объекта синхронизации.

Кусок кода (только добавленные/исправленные методы):
Код
        
private void OnNewPortfolios(IEnumerable<Portfolio> portfolios)
        {
            portfolios.ForEach(portfolio => Trader.RegisterPortfolio(portfolio));
        }

		/// <summary>
		/// Запустить накопление маркет-данных.
		/// </summary>
		public void Start()
		{
			Trader = _createTrader();

			try
			{
				((BaseTrader)Trader).EntityFactory = new MarketDataEntityFactory(_securityStorage);

				Trader.ProcessDataError += OnError;
				Trader.Connected += OnConnected;
				Trader.NewTrades += OnNewTrades;
				Trader.QuotesChanged += OnQuotesChanged;
                Trader.NewPortfolios += OnNewPortfolios;

                using (var su = new SecurityUpdate(Trader))
                {                    

                    Trader.Connect();

                    lock (_connectedLock)
                    {
                        if (!Trader.IsConnected && !Monitor.Wait(_connectedLock, TimeSpan.FromSeconds(20)))
                            throw new TimeoutException("Ожидание подключения превысило максимально допустимый интервал.");
                    }

                    su.Run();
                }
               
			}
			catch
			{
				Trader.Dispose();
				throw;
			}
		}
		
		/// <summary>
		/// Остановить накопление маркет-данных.
		/// </summary>
		public void Stop()
		{
            foreach (Portfolio portfolio in Trader.Portfolios) Trader.UnRegisterPortfolio(portfolio);

			Trader.ProcessDataError -= OnError;
			Trader.Connected -= OnConnected;
			Trader.NewTrades -= OnNewTrades;
			Trader.QuotesChanged -= OnQuotesChanged;
            Trader.NewPortfolios -= OnNewPortfolios;

			Trader.Dispose();

			LastError = null;
		}

		private sealed class SecurityUpdate : Disposable
		{
			private readonly ITrader _trader;

            private readonly object _securitiesLock = new object();
             
			public SecurityUpdate(ITrader trader)
			{
				_trader = trader;
				_trader.NewSecurities += OnNewSecurities;
			}

			public void Run()
			{
                int waitSeconds = 180;  // initial delay

				while (true)
				{
					Thread.Sleep(500);
                    lock (_securitiesLock)
                    {
                        if (!Monitor.Wait(_securitiesLock, TimeSpan.FromSeconds(waitSeconds)))
                            break;

                        waitSeconds = 30;  // if we have received a first portion of data, change delay to 30 seconds
                    }
				}
			}

			void OnNewSecurities(IEnumerable<Security> securities)
			{
                lock (_securitiesLock)
                    Monitor.PulseAll(_securitiesLock);
			}

			protected override void DisposeManaged()
			{
				_trader.NewSecurities -= OnNewSecurities;
			}
		}

Теги:


Спасибо:


Mikhail Sukhov

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


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


Лучше через логин на КодеПлексе, сами закоммитите. Думаю, не в первый и не в последний раз будете Гидру править. Там много что еще нужно доделывать.

По коду ряд замечаний:

1. Портфели тут явно не причем. Зачем было вызывать их экспорт?
2. Проблема с появлением инструментов в Sleep. Sleep замораживает поток. Wait - блокирует (но он продолжает "жить"). Соответственно, COM события не могут отправиться, так как оконный поток заморожен. Зачем вы Sleep оставили я так и не понял.
Спасибо:

Marco

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


Ага, на CodePlex я зарегистрировался, логин - donmarco. Нужны от меня еще какие-либо шаги, чтобы получить доступ к репозиторию на запись? Есть ли какой-нибудь регламент работы над проектом (ветки и т.д.)?

За замечания спасибо. :) Портфели - я думал, что нужно их регистрировать для получения списка бумаг. Проверил - действительно портфели ни при чем. Что касается Sleep'а - я не знал, как планируются потоки в .Net, почитаю документацию. В native-коде вызов sleep привел бы к переключению потока. Здесь он действительно не нужен.
Спасибо:

Mikhail Sukhov

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


Marco
Ага, на CodePlex я зарегистрировался, логин - donmarco. Нужны от меня еще какие-либо шаги, чтобы получить доступ к репозиторию на запись? Есть ли какой-нибудь регламент работы над проектом (ветки и т.д.)?


Доступ дал. Инструкция на сайте. Регламент простой, табы вместо пробелов, код проверяем R#-ом.

Marco

За замечания спасибо. :) Портфели - я думал, что нужно их регистрировать для получения списка бумаг. Проверил - действительно портфели ни при чем. Что касается Sleep'а - я не знал, как планируются потоки в .Net, почитаю документацию. В native-коде вызов sleep привел бы к переключению потока. Здесь он действительно не нужен.


Sleep - это и есть native код.
Спасибо:

Marco

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


Спасибо. Как только немного разберусь с .Net, CodePlex и Hydra, буду коммитить.
Спасибо:


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

loading
clippy