Обновление инструментов через SmartCOM
Столкнулся с тем, что 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;
}
}