← Back

Получение стакана Фортс.

Продолжаю ковырять SampleConsole, и столкнулся я вот с этим "Если код и класс инструмента содержат символ @, то рекомендуется поменять разделитель на другой символ через свойство SecurityIdGenerator....Delimiter у BaseTrader....SecurityIdGenerator. " , а как сие применить примера нема.В общем нужно получить стакан srh2@rts в sampleconsole.Может кто кусок кода кинет по теме?

Comments (27)

Login or Create account, Log in or register to leave a comment

Supervisor
Supervisor

Ничего там переопределять не нужно, ни код ни класс у srh2 не содержат знаков @

wkj
wkj Author

В хелпе по экспорту стакана именно так(srh2@rts) фьючи выводятся, и Verifier ругается если в заголовке стакана видит просто Srh2.А если выводить стакан при запущенной SampleConsole, dde не находит лист srh2@rts.Нужно как-то применить "SecurityIdGenerator.Delimiter" видимо, чтоб @ на что-то другое заменить ибо Vs на @ как-то не так смотрит 😟 .

vader
vader

ТАк поставтье в имени таблицы - SRH2@RTS Все будет прекрасно выводится.

wkj
wkj Author

vader: ТАк поставтье в имени таблицы - SRH2@RTS Все будет прекрасно выводится. Такой заголовок и стоит.Опишу свои действия степ-бай-степ: в Sampleconsole Lkoh заменен на Srh2, в Квик добавлен стакан сбера с заголовком Srh2@Rts(продажа,цена,покупка,покупки показывать сверху).Запускаю консоль ввожу spbfutxxx,проскакивает окно дде стакана и всё останавливается на "Дожидаемся появления инструмента и портфеля".Вот )

vader
vader

Сделал все, как у вас описано - у меня все прекрасно работает. Попробуйте сделать так. Скачайте последную версию S#. Загрузите файл с настройками Квика, чтобы получить правильные таблицы. Стакан не открывайте, программа сама его откроет. Только поменяйте инстумет в примере и все.

wkj
wkj Author

Сделал как вы сказали, попробовал 4.0.18, опять уперся в "Дожидаемся появления в программе инструмента и портфеля". Все 3 раза проверил, таблицы из стоковского ванда,в общем я в прострации.

vader
vader

Я тоже. А что такое стоковский ванд?

wkj
wkj Author

vader: Я тоже. А что такое стоковский ванд? Wnd файл.

wkj
wkj Author

Я подозреваю что ответ тут http://stocksharp.com/forum/2292/Stakan-FORTS-voobshchie-rabotaiet/ кроется но разглядеть руководство к действию не могу. Но там человек стакан сам вроде в квике открывал.

Moadip
Moadip

Попробовал запустить SampleConsole Поменял на SRH2

const string secCode = "SRH2";

Запустил, все отрабатывает нормально. В квике стакан открыт.

Закрыл стакан, запустил, стакан открылся автоматом и все отработало как надо.

У вас в таблице "Инструменты" фьючерс SRH2 есть?

wkj
wkj Author

В таблице "Инструменты" фьючерс SRH2 есть. Приложу листинг может пропустил что.Кстати как код выкладывать цивилизовано? namespace SampleConsole { using System; using System.Linq; using System.Threading;

using Ecng.Common;

using StockSharp.BusinessEntities;
using StockSharp.Quik;
using StockSharp.Algo;

class Program
{
	private static Security _srh2;
	private static Portfolio _portfolio;
	private static MarketDepth _depth;

	static void Main()
	{
		try
		{
			// для теста выбираем бумагу Лукойл
			const string secCode = "SRH2";

			var quikPath = QuikTerminal.GetDefaultPath();

			if (quikPath.IsEmpty())
			{
				Console.WriteLine("Не найден ни один запущенный Quik");
				return;
			}

			Console.WriteLine("Запущенный Quik найден по пути " + quikPath);

			Console.Write("Введите код клиента, через который будет выставлена заявка: ");
			var account = Console.ReadLine();

			using (var waitHandle = new AutoResetEvent(false))
			{
				// создаем шлюз к Quik-у
				using (var trader = new QuikTrader(quikPath))
				{
					// необходимо раскомментировать, если идет работа с РТС Стандарт
					//trader.FormatTransaction += builder => builder.RemoveInstruction(TransactionBuilder.ExecutionCondition);

					// подписываемся на событие успешного подключения
					// все действия необходимо производить только после подключения
					trader.Connected += () =>
					{
						Console.WriteLine("Подключение было произведено успешно.");

						// извещаем об успешном соединени
						waitHandle.Set();
					};

					Console.WriteLine("Производим подключение...");

					trader.Connect();

					// дожидаемся события об успешном соединении
					waitHandle.WaitOne();

					trader.NewPortfolios += portfolios =>
					{
						if (_portfolio == null)
						{
							// находим Лукойл и присваиваем ее переменной lkoh
							_portfolio = portfolios.FirstOrDefault(p => p.Name == account);

							if (_portfolio != null)
							{
								Console.WriteLine("Портфель {0} появился.", account);

								// если инструмент и стакан уже появились,
								// то извещаем об этом основной поток для выставления заявки
								if (_srh2 != null && _depth != null)
									waitHandle.Set();
							}
						}
					};

					// подписываемся на событие появление инструментов
					trader.NewSecurities += securities =>
					{
                        if (_srh2 == null)
						{
							// находим Лукойл и присваиваем ее переменной lkoh
                            _srh2 = securities.FirstOrDefault(sec => sec.Code == secCode);

                            if (_srh2 != null)
							{
								Console.WriteLine("Инструмент SRH2 появился.");

								// запускаем экспорт стакана
                                trader.RegisterQuotes(_srh2);

								if (_portfolio != null && _depth != null)
									waitHandle.Set();
							}
						}
					};

					// подписываемся на событие появления моих новых сделок
					trader.NewMyTrades += myTrades =>
					{
						foreach (var myTrade in myTrades)
						{
							var trade = myTrade.Trade;
							Console.WriteLine("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}.", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
						}
					};

					// подписываемся на событие обновления стакана
					trader.QuotesChanged += depths =>
					{
                        if (_depth == null && _srh2 != null)
						{
                            _depth = depths.FirstOrDefault(d => d.Security == _srh2);

							if (_depth != null)
							{
								Console.WriteLine("Стакан SRH2 появился.");

								// если портфель и инструмент уже появился, то извещаем об этом основной поток для выставления заявки
                                if (_portfolio != null && _srh2 != null)
									waitHandle.Set();
							}
						}
					};

					Console.WriteLine("Дожидаемся появления в программе инструмента Лукойл и портфеля {0}...".Put(account));

					// запускаем экспорт по DDE
					trader.StartExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
					                   trader.EquityPortfoliosTable, trader.OrdersTable);

					// дожидаемся появления портфеля и инструмента
					waitHandle.WaitOne();

					// 0.1% от изменения цены
					const decimal delta = 0.001m;

					// запоминаем первоначальное значение середины спреда
                    var firstMid = _srh2.BestPair.SpreadPrice / 2;
                    if (_srh2.BestBid == null)
						throw new Exception("Нет лучшего бида для котировки.");

                    Console.WriteLine("Первоначальное значение середины спреда {0:0.##}", _srh2.BestBid.Price + firstMid);

					while (true)
					{
                        var mid = _srh2.BestPair.SpreadPrice / 2;

						// если спред вышел за пределы нашего диапазона
						if	(
								((firstMid + firstMid * delta) <= mid) ||
								((firstMid - firstMid * delta) >= mid)
							)
						{
							var order = new Order
							{
								Portfolio = _portfolio,
                                Price = _srh2.ShrinkPrice(_srh2.BestBid.Price + mid),
                                Security = _srh2,
								Volume = 1,
								Direction = OrderDirections.Buy,
							};
							trader.RegisterOrder(order);
							Console.WriteLine("Заявка {0} зарегистрирована.", order.Id);
							break;
						}
						else
                            Console.WriteLine("Текущее значение середины спреда {0:0.##}", _srh2.BestBid.Price + mid);

						// ждем 1 секунду
						Thread.Sleep(1000);
					}

					// останавливаем экспорт по DDE
					trader.StopExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
					                  trader.EquityPortfoliosTable, trader.OrdersTable);
				}
			}
		}
		catch (Exception ex)
		{
			Console.WriteLine(ex);
		}
	}
}

}

vader
vader

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

После того, как вы стака отредактировали ,вы нажимаете кнопку "Начать вывод" ?

Moadip
Moadip

Попробовал скопипастить ваш код и запустить. В итоге работа программы остановилась на "стакан SRH2 появился". Запускаю оригинальный пример просто с изменением инструмента. То же самое.😳

Ставлю бряк на вход в обработчик события NewPortfolios и наблюдаю следующуюю картину.

Событие сработало, нашелся портфель ММВБ. Но после этого, событие больше не срабатывало. Хотя должно было, и должен был найден портфель FORTS

Проблема оказалась в следующем. Есть вот такие куски кода


trader.StartExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
		  trader.EquityPortfoliosTable, trader.OrdersTable);

...

trader.StopExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
		  trader.EquityPortfoliosTable, trader.OrdersTable);

Так вот в оригинальном примере по dde выводятся таблицы "портфель по бумагам" и "позиции по бумагам" - trader.EquityPositionsTable, trader.EquityPortfoliosTable

Чтобы работать с фьючерсами, надо добавить еще две таблицы trader.DerivativePositionsTable и trader.DerivativePortfoliosTable


trader.StartExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
		  trader.EquityPortfoliosTable, trader.OrdersTable, trader.DerivativePositionsTable, trader.DerivativePortfoliosTable);

...

trader.StopExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
		  trader.EquityPortfoliosTable, trader.OrdersTable, trader.DerivativePositionsTable, trader.DerivativePortfoliosTable);

Или сделать проще


trader.StartExport();

...

trader.StopExport();

И все будет работать.

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

Начинаю разбираться. Удаляю таблицы по деривативам, запускаю, пример отрабатывает как надо.😳 Ставлю опять бряк на вход в обработчик события NewPortfolios. Смотрю, находится портфель по FORTS. Смотрю в квике запущен ли экспорт по таблицам деривативов - нет, не запущен.🤨

Оказывается. Даже если не запущен экспорт dde по таблицам деривативов, то если есть хоть одна заявка в таблице "Заявки", то номер счета будет браться оттуда.

<u>Это фича или баг?</u>

Проверил следующим образом, удалил таблицу заявок из экспорта - trader.OrdersTable. Запустил и программа не отработала как надо. Поэтому у меня вчера пример отработал без проблем, т.к. были сделки по FORTS.

wkj Yury Smykalov
Alexander
Alexander

Это не фича и не баг. Это то как работает QuikTrader - строит информацию по той таблице, которая пришла первой.

Moadip
Moadip

Ок. Понятно.

wkj
wkj Author

И снова здравствуйте 🎉 ! Спасибо vader и Moadip за внимание к проблеме.Я опять с плохими новостями. Если использовать <mark>trader.StartExport(); trader.StopExport(); </mark> то упираюсь в "Портфель ХХХ появился" а после закрытия консоли квик выдает - DDE сервер 'STOCKSHARP'. Документ 'все сделки[]'. Таблица 'Все сделки'. Ошибка при передаче таблицы,вывод приостановлен. Неверные параметры. И еще 'Переполнена очередь сообщений', и еще что-то про переполнение сервера что я не смог воспроизвести и записать. А при использовании старт экспорта с перечислением таблиц, также упираюсь в "Портфель ХХХ появился" но после закрытия консоли квик ошибок не выдает. Verifier говорит все хорошо. На всякий случай оставил в таблице всех сделок только сбер. Кто что думает?

Moadip
Moadip

Оригинальный пример SampleConsole как работает? Нормально или нет?

wkj
wkj Author

Moadip: Оригинальный пример SampleConsole как работает? Нормально или нет? У меня только Фортс включен.

Moadip
Moadip

Для всех экспериментов лучше поставить демо квик. На боевом как то неохото тренироваться в отладке кода.

wkj
wkj Author

Moadip: Для всех экспериментов лучше поставить демо квик. На боевом как то неохото тренироваться в отладке кода. Мне особо рисковать там нечем, отношусь как к демо 😀 .

Moadip
Moadip

Поставьте демо квик(закажите доступ на сайте квик). Сначала будет только ММВБ. Потом дня через два подключат фортс. Проверьте как работает оригинальный пример SampleConsole, чтобы исключить ошибки на начальном этапе.

Mikhail Sukhov
Mikhail Sukhov

Moadip: Поставьте демо квик(закажите доступ на сайте квик). Сначала будет только ММВБ. Потом дня через два подключат фортс. Проверьте как работает оригинальный пример SampleConsole, чтобы исключить ошибки на начальном этапе.

Тестировать нагляднее лучше на Sample. Но понять его сложнее.

wkj
wkj Author

Сейчас попробовал после загрузки консоли до "Портфель ХХХ получен"(здесь у меня всё и встаёт)вывеси стакан вручную и получил "Не удалось установить DDЕ соединение с сервером 'wrapper'.Либо не запущен 'стакан', либо в него не загружен лист 'SRH2@RTS'. Таблица 'SRH2@RTS'". Неужели все это действительно работает 🤬 ? Verifier говорит ок. Ну и код еще раз на всякий.


namespace SampleConsole
{
	using System;
	using System.Linq;
	using System.Threading;
	using Ecng.Common;
        using StockSharp.BusinessEntities;
	using StockSharp.Quik;
	using StockSharp.Algo;

	class Program
	{
		private static Security _SRH2;
		private static Portfolio _portfolio;
		private static MarketDepth _depth;
        static void Main()
		{
			try
			{
				// для теста выбираем бумагу SRH2
				const string secCode = "SRH2";

				var quikPath = QuikTerminal.GetDefaultPath();

				if (quikPath.IsEmpty())
				{
					Console.WriteLine("Не найден ни один запущенный Quik");
					return;
				}

				Console.WriteLine("Запущенный Quik найден по пути " + quikPath);

				Console.Write("Введите код клиента, через который будет выставлена заявка: ");
				var account = Console.ReadLine();

				using (var waitHandle = new AutoResetEvent(false))
				{
					// создаем шлюз к Quik-у
					using (var trader = new QuikTrader(quikPath))
					{
						// необходимо раскомментировать, если идет работа с РТС Стандарт
						//trader.FormatTransaction += builder => builder.RemoveInstruction(TransactionBuilder.ExecutionCondition);

						// подписываемся на событие успешного подключения
						// все действия необходимо производить только после подключения
						trader.Connected += () =>
						{
							Console.WriteLine("Подключение было произведено успешно.");

							// извещаем об успешном соединени
							waitHandle.Set();
						};

						Console.WriteLine("Производим подключение...");

						trader.Connect();

						// дожидаемся события об успешном соединении
						waitHandle.WaitOne();

						trader.NewPortfolios += portfolios =>
						{
							if (_portfolio == null)
							{
								// находим Лукойл и присваиваем ее переменной Srh2
								_portfolio = portfolios.FirstOrDefault(p => p.Name == account);

								if (_portfolio != null)
								{
									Console.WriteLine("Портфель {0} появился.", account);

									// если инструмент и стакан уже появились,
									// то извещаем об этом основной поток для выставления заявки
									if (_SRH2 != null && _depth != null)
										waitHandle.Set();
								}
							}
						};

						// подписываемся на событие появление инструментов
						trader.NewSecurities += securities =>
						{
                            if (_SRH2 == null)
							{
								// находим Лукойл и присваиваем ее переменной Srh2
                                _SRH2 = securities.FirstOrDefault(sec => sec.Code == secCode);

                                if (_SRH2 != null)
								{
									Console.WriteLine("Инструмент SRH2 появился.");

									// запускаем экспорт стакана
                                    trader.RegisterQuotes(_SRH2);

									if (_portfolio != null && _depth != null)
										waitHandle.Set();
								}
							}
						};

						// подписываемся на событие появления моих новых сделок
						trader.NewMyTrades += myTrades =>
						{
							foreach (var myTrade in myTrades)
							{
								var trade = myTrade.Trade;
								Console.WriteLine("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}.", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
							}
						};

						// подписываемся на событие обновления стакана
						trader.QuotesChanged += depths =>
						{
                            if (_depth == null && _SRH2 != null)
							{
                                _depth = depths.FirstOrDefault(d => d.Security == _SRH2);

								if (_depth != null)
								{
									Console.WriteLine("Стакан SRH2 появился.");

									// если портфель и инструмент уже появился, то извещаем об этом основной поток для выставления заявки
                                    if (_portfolio != null && _SRH2 != null)
										waitHandle.Set();
								}
							}
						};

						Console.WriteLine("Дожидаемся появления в программе инструмента SRH2 и портфеля {0}...".Put(account));
                       // запускаем экспорт по DDE
					//trader.StartExport();     
                    trader.StartExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
           trader.EquityPortfoliosTable, trader.OrdersTable, trader.DerivativePositionsTable, trader.DerivativePortfoliosTable);

						// дожидаемся появления портфеля и инструмента
						waitHandle.WaitOne();

						// 0.1% от изменения цены
						const decimal delta = 0.001m;

						// запоминаем первоначальное значение середины спреда
                        var firstMid = _SRH2.BestPair.SpreadPrice / 2;
                        if (_SRH2.BestBid == null)
							throw new Exception("Нет лучшего бида для котировки.");

                        Console.WriteLine("Первоначальное значение середины спреда {0:0.##}", _SRH2.BestBid.Price + firstMid);

						while (true)
						{
                            var mid = _SRH2.BestPair.SpreadPrice / 2;

							// если спред вышел за пределы нашего диапазона
							if	(
									((firstMid + firstMid * delta) <= mid) ||
									((firstMid - firstMid * delta) >= mid)
								)
							{
								var order = new Order
								{
									Portfolio = _portfolio,
                                    Price = _SRH2.ShrinkPrice(_SRH2.BestBid.Price + mid),
                                    Security = _SRH2,
									Volume = 1,
									Direction = OrderDirections.Buy,
								};
								trader.RegisterOrder(order);
								Console.WriteLine("Заявка {0} зарегистрирована.", order.Id);
								break;
							}
							else
                                Console.WriteLine("Текущее значение середины спреда {0:0.##}", _SRH2.BestBid.Price + mid);

							// ждем 1 секунду
							Thread.Sleep(1000);
						}

						// останавливаем экспорт по DDE
                   // trader.StopExport();
                
                        trader.StopExport(trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable,
              trader.EquityPortfoliosTable, trader.OrdersTable, trader.DerivativePositionsTable, trader.DerivativePortfoliosTable);
                    
                
                      }
                    
                      
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
			}
		}
	}
}

wkj
wkj Author

Докладываю на случай появления розовых с моего юзерпика. В квик был подгружен приложенный к библиотеке ванд и на этом настройку я посчитал законченной(прочитав это <mark>Данный файл уже содержит настройки программы Quik, и не требуется самостоятельная настройка таблиц</mark> ) не добавив свой любимый сбер в таблицу инструменты. Теперь все работает и даже удалось рубль заработать😀. В документацию стоит добавить что самостоятельно придется добавить торгуемые инструменты.

Algonavt
Algonavt

Добрый день!

Пробую получать данные по инструменту как "RIM2" - ничего. Если имя инструмента задать как "RTS-6.12", все работает.

Для инструментов ММВБ такой проблемы нет - поиск по LKOH, SBER, SBERP и другим результат дает исправно (экспорт по DDE запускается, стакан появляется).

Как побороть?

Zyanov
Zyanov

Algonavt: Добрый день! Если имя инструмента задать как "RTS-6.12", все работает. Как побороть? У некоторых брокеров инструменты фортс имеют такие названия, если все работает может оставить так?

Кот Матроскин

Zyanov:

Algonavt: Добрый день! Если имя инструмента задать как "RTS-6.12", все работает. Как побороть? У некоторых брокеров инструменты фортс имеют такие названия, если все работает может оставить так? Странно, должно быть RIM2