← Назад

SampleRealTimeTesting sample после миграции со SmartCOM на QUIK выдает исключение в недрах S#. API

Не знаю, насколько тут уместно постить такое. Пытаюсь разобраться с примерами (ну и понять, смогу ли я работать с таким API). В общем пытаюсь перевести SimpleRealTimeTesting со SmartCOM на QUIK. В результате получаю исключение из недр обфусцированного кода:


Ошибка обработки данных

System.InvalidCastException: Specified cast is not valid.

at StockSharp.Algo.Testing.MarketEmulator.#=qs6NzRPBUoQ97T6nLH2BXpdtViDMxlBeB2SExFBHpRbs=.#=q7j8EZbErbhHRqBgBllTfPQ==(Message #=qFQNVQcmMx$w5TCZAXAka$w==, ICollection`1 #=qRIzQ1Vh6LxB082hZhWuGCw==)

at StockSharp.Algo.Testing.MarketEmulator.#=qs6NzRPBUoQ97T6nLH2BXpdtViDMxlBeB2SExFBHpRbs=.#=qIoakeHStFXUa2AHCKtSOdeQTtljz6NCiG3BQadYRn1nAyHWoqu4FDXdnHAk7VIwVHhs22v7wgoRTEod9oBwpFg==(Message #=qEU2PbcRHgieaeZXSjz7SIQ==)

at StockSharp.Algo.Testing.MarketEmulator.#=qf8FBDiLuwFV_pI1sqDDhMrxGHa5ZJ9z$AV68KOW7ejSUVtF2Mf18_A0jyIaKkzavqxn_yyIY0YlX$A7mV7dnGg==(Message #=qchosc_KrDpyII45LSsUmJg==)

at StockSharp.Algo.Testing.EmulationMessageAdapter.OnSendInMessage(Message message)

at StockSharp.Messages.MessageAdapter`1.OnInMessageProcessor(Message message, IMessageAdapter adapter)


OK

По идее хорошо бы тут говорить, что именно ожидается в данном случае. Какое сообщение. А то отладка ну совершенно странной становится. :)

Код получился вот такой: (заменил класс трейдера, прописал путь к терминалу и отключил загрузку исторических свечей - может в этом дело?):

using StockSharp.Quik;

namespace SampleRealTimeTesting
{
	using System;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Diagnostics;
	using System.Linq;
	using System.Windows;

	using Ecng.Collections;
	using Ecng.Common;
	using Ecng.ComponentModel;
	using Ecng.Xaml;

	using StockSharp.Algo;
	using StockSharp.Algo.Candles;
	using StockSharp.Algo.Indicators;
	using StockSharp.Algo.Indicators.Trend;
	using StockSharp.Algo.Reporting;
	using StockSharp.Algo.Testing;
	using StockSharp.BusinessEntities;
	using StockSharp.Logging;
	using StockSharp.Messages;
	
	using StockSharp.Xaml.Charting;

	public partial class MainWindow
	{
		private bool _isConnected;
        private readonly TimeSpan _timeFrame = TimeSpan.FromMinutes(5);
		private readonly SynchronizedList<TimeFrameCandle> _historyCandles = new SynchronizedList<TimeFrameCandle>();
		private CandleManager _candleManager;
        private RealTimeEmulationTrader<QuikTrader> _trader;
		private SmaStrategy _strategy;
		private DateTime _lastHistoryCandle;
		private Security _lkoh;
		private readonly ChartArea _area;
		private ChartCandleElement _candlesElem;
		private ChartIndicatorElement _longMaElem;
		private ChartIndicatorElement _shortMaElem;

		public MainWindow()
		{
			InitializeComponent();

			_area = new ChartArea();
			_chart.Areas.Add(_area);
		}

		protected override void OnClosing(CancelEventArgs e)
		{
			if (_trader != null)
				_trader.Dispose();

			base.OnClosing(e);
		}

		private void ConnectClick(object sender, RoutedEventArgs e)
		{
			if (!_isConnected)
			{
				if (_trader == null)
				{
                    //if (Login.Text.IsEmpty())
                    //{
                    //    MessageBox.Show(this, "Не указан логин.");
                    //    return;
                    //}
                    //else if (Password.Password.IsEmpty())
                    //{
                    //    MessageBox.Show(this, "Не указан пароль.");
                    //    return;
                    //}

					// тестовый портфель
					var portfolio = new Portfolio
					{
						Name = "test account",
						BeginValue = 1000000,
					};

					// создаем подключение
                    _trader = new RealTimeEmulationTrader<QuikTrader>(new QuikTrader
					(@"C:\Users\nryabkov\Documents\QUIK NetTrader\info.exe"));

					var logManager = new LogManager();
					logManager.MaxMessageCount = -1;			// без этого будет буферизация логов и они будут неактуальны при остановке в дебаггере.
					logManager.Listeners.Add(new FileLogListener("sample.log"));
					logManager.Sources.Add(_trader);

					// очищаем из текстового поля в целях безопасности
					Password.Clear();

					// подписываемся на событие успешного соединения
					_trader.Connected += () =>
					{
						// возводим флаг, что соединение установлено
						_isConnected = true;

						// разблокируем кнопку Экспорт
						this.GuiAsync(() => ChangeConnectStatus(true));

						// передаем первоначальное значение размера портфеля в эмулятор
						_trader.TransactionAdapter.SendInMessage(portfolio.ToMessage());
						_trader.TransactionAdapter.SendInMessage(new PortfolioChangeMessage
						{
							PortfolioName = portfolio.Name
						}.Add(PositionChangeTypes.BeginValue, portfolio.BeginValue));

						_candleManager = new CandleManager(_trader);

                        //_trader.UnderlyingConnector.NewCandles += (series, candles) => _historyCandles.SyncDo(col =>
                        //{
                        //    _historyCandles.AddRange(candles.Cast<TimeFrameCandle>());

                        //    this.GuiAsync(() =>
                        //    {
                        //        foreach (var candle in candles)
                        //            ProcessCandle(candle);
                        //    });
                        //});

						_trader.NewSecurities += securities => this.GuiAsync(() =>
						{
							// находим нужную бумагу
							var lkoh = securities.FirstOrDefault(s => s.Code == "LKOH");

							if (lkoh != null)
							{
								_lkoh = lkoh;

								this.GuiAsync(() =>
								{
									Start.IsEnabled = true;
								});
							}
						});

						_trader.NewMyTrades += trades => this.GuiAsync(() =>
						{
							if (_strategy != null)
							{
								// найти те сделки, которые совершила стратегия скользящей средней
								trades = trades.Where(t => _strategy.Orders.Any(o => o == t.Order));

								_trades.Trades.AddRange(trades);
							}
						});

						// подписываемся на событие о неудачной регистрации заявок
						_trader.OrdersRegisterFailed += OrdersFailed;

						_candleManager.Processing += (s, candle) =>
						{
							// выводим только те свечки, которые не были отрисованы как исторические
							if (candle.OpenTime > _lastHistoryCandle)
								ProcessCandle(candle);
						};

						_trader.StartExport();

						this.GuiAsync(() =>
						{
							ConnectBtn.IsEnabled = false;
						});
					};

					// подписываемся на событие разрыва соединения
					_trader.ConnectionError += error => this.GuiAsync(() =>
					{
						// заблокируем кнопку Экспорт (так как соединение было потеряно)
						ChangeConnectStatus(false);

						MessageBox.Show(this, error.ToString(), "Ошибка соединения");
					});

					_trader.ProcessDataError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString(), "Ошибка обработки данных"));
				}

				_trader.Connect();
			}
			else
			{
				_trader.Disconnect();
			}
		}

		private void OrdersFailed(IEnumerable<OrderFail> fails)
		{
			this.GuiAsync(() =>
			{
				foreach (var fail in fails)
					MessageBox.Show(this, fail.Error.ToString(), "Ошибка регистрации заявки");
			});
		}

		private void ChangeConnectStatus(bool isConnected)
		{
			_isConnected = isConnected;
			ConnectBtn.Content = isConnected ? "Отключиться" : "Подключиться";
		}

		private void OnLog(LogMessage message)
		{
			// если стратегия вывела не просто сообщение, то вывести на экран.
			if (message.Level != LogLevels.Info && message.Level != LogLevels.Debug)
				this.GuiAsync(() => MessageBox.Show(this, message.Message));
		}

		private void OnStrategyPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			this.GuiAsync(() =>
			{
				Status.Content = _strategy.ProcessState;
				PnL.Content = _strategy.PnL;
				Slippage.Content = _strategy.Slippage;
				Position.Content = _strategy.Position;
				Latency.Content = _strategy.Latency;
			});
		}

		private void StartClick(object sender, RoutedEventArgs e)
		{
			// если были получены и инструмент, и портфель
			if (_strategy == null)
			{
				// создаем скользящие средние, на 80 5-минуток и 10 5-минуток
				var longSma = new SimpleMovingAverage { Length = 80 };
				var shortSma = new SimpleMovingAverage { Length = 10 };
				
				// регистрируем наш тайм-фрейм
				var series = new CandleSeries(typeof(TimeFrameCandle), _lkoh, _timeFrame);
				// создаем торговую стратегию
				_strategy = new SmaStrategy(series, longSma, shortSma)
				{
					Volume = 1,
					Security = _lkoh,
					Portfolio = _trader.Portfolios.First(),
					Connector = _trader,
				};
				_strategy.Log += OnLog;
				_strategy.PropertyChanged += OnStrategyPropertyChanged;

				_candlesElem = new ChartCandleElement();
				_area.Elements.Add(_candlesElem);

				_longMaElem = new ChartIndicatorElement
				{
					Title = "Длинная",
					Indicator = _strategy.LongSma,
				};
				_area.Elements.Add(_longMaElem);

				_shortMaElem = new ChartIndicatorElement
				{
					Title = "Короткая",
					Indicator = _strategy.ShortSma,
				};
				_area.Elements.Add(_shortMaElem);

				// начинаем получать текущие сделки (для построения свечек реального времени)
				_trader.RegisterTrades(_lkoh);

                //// делаем запрос в SmartCOM для получения исторических данных по 5-минуткам для Лукойла за период в 5 дней
                //_trader.UnderlyingConnector.RequestCandles(_lkoh, SmartComTimeFrames.Minute5,
                //                     new Range<DateTime>(DateTime.Today - TimeSpan.FromDays(5), _lkoh.GetMarketTime()));

				_lastHistoryCandle = _timeFrame.GetCandleBounds(_lkoh).Min;

				Report.IsEnabled = true;
			}

			if (_strategy.ProcessState == ProcessStates.Stopped)
			{
				// запускаем процесс получения стакана, необходимый для работы алгоритма котирования
				_trader.RegisterMarketDepth(_strategy.Security);
				_strategy.Start();
				Start.Content = "Стоп";
			}
			else
			{
				_trader.UnRegisterMarketDepth(_strategy.Security);
				_strategy.Stop();
				Start.Content = "Старт";
			}
		}

		private void ProcessCandle(Candle candle)
		{
			var longValue = candle.State == CandleStates.Finished ? new ChartIndicatorValue(_strategy.LongSma, _strategy.LongSma.Process(candle)) : null;
			var shortValue = candle.State == CandleStates.Finished ? new ChartIndicatorValue(_strategy.ShortSma, _strategy.ShortSma.Process(candle)) : null;

			_chart.ProcessValues(candle.OpenTime, new Dictionary<IChartElement, object>
			{
				{ _candlesElem, candle },
				{ _longMaElem, longValue },
				{ _shortMaElem, shortValue },
			});
		}

		private void ReportClick(object sender, RoutedEventArgs e)
		{
			// сгерерировать отчет по прошедшему тестированию
			new ExcelStrategyReport(_strategy, "sma.xls").Generate();

			// открыть отчет
			Process.Start("sma.xls");
		}
	}
}

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

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

esper
esper

Какая версия?

nryabkov
nryabkov Автор

Версия 4.2.2.16

esper
esper

Обновитесь до последней версии.

nryabkov
nryabkov
nryabkov Автор

Да, большое спасибо. Заработало! :)