static void Main() { try { // для теста выбираем бумагу Лукойл const string secCode = "LKOH"; var quikPath = QuikTerminal.GetDefaultPath(); if (quikPath.IsEmpty()) { Console.WriteLine(LocalizedStrings.Str2984); return; } Console.WriteLine(LocalizedStrings.Str2985.Put(quikPath)); Console.Write(LocalizedStrings.Str2986); var account = Console.ReadLine(); using (var waitHandle = new AutoResetEvent(false)) { // создаем подключение к Quik-у using (var trader = new QuikTrader(quikPath) { IsDde = true }) { // необходимо раскомментировать, если идет работа с РТС Стандарт //trader.FormatTransaction += builder => builder.RemoveInstruction(Transaction.TimeInForce); // подписываемся на событие успешного подключения // все действия необходимо производить только после подключения trader.Connected += () => { Console.WriteLine(LocalizedStrings.Str2169); // извещаем об успешном соединени waitHandle.Set(); }; Console.WriteLine(LocalizedStrings.Str2170); trader.DdeTables = new[] { trader.SecuritiesTable, trader.MyTradesTable, trader.EquityPositionsTable, trader.EquityPortfoliosTable, trader.OrdersTable }; trader.Connect(); // дожидаемся события об успешном соединении waitHandle.WaitOne(); trader.NewPortfolio += portfolio => { if (_portfolio == null && portfolio.Name == account) { // находим нужный портфель и присваиваем его переменной _portfolio _portfolio = portfolio; Console.WriteLine(LocalizedStrings.Str2171Params, account); // если инструмент и стакан уже появились, // то извещаем об этом основной поток для выставления заявки if (_lkoh != null && _depth != null) { waitHandle.Set(); } } }; // подписываемся на событие появление инструментов trader.NewSecurity += security => { if (_lkoh == null) { if (!security.Code.CompareIgnoreCase(secCode)) { return; } // находим Лукойл и присваиваем ее переменной lkoh _lkoh = security; if (_lkoh != null) { Console.WriteLine(LocalizedStrings.Str2987); // запускаем экспорт стакана trader.RegisterMarketDepth(_lkoh); if (_portfolio != null && _depth != null) { waitHandle.Set(); } } } }; // подписываемся на событие появления моих новых сделок trader.NewMyTrade += myTrade => { var trade = myTrade.Trade; Console.WriteLine(LocalizedStrings.Str2173Params, trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time); }; // подписываемся на событие обновления стакана trader.MarketDepthChanged += depth => { if (_depth == null && _lkoh != null && depth.Security == _lkoh) { _depth = depth; Console.WriteLine(LocalizedStrings.Str2988); // если портфель и инструмент уже появился, то извещаем об этом основной поток для выставления заявки if (_portfolio != null && _lkoh != null) { waitHandle.Set(); } } }; Console.WriteLine(LocalizedStrings.Str2989Params.Put(account)); // дожидаемся появления портфеля и инструмента waitHandle.WaitOne(); // 0.1% от изменения цены const decimal delta = 0.001m; // запоминаем первоначальное значение середины спреда var firstMid = _lkoh.BestPair.SpreadPrice / 2; if (_lkoh.BestBid == null || firstMid == null) { throw new Exception(LocalizedStrings.Str2990); } Console.WriteLine(LocalizedStrings.Str2991Params, _lkoh.BestBid.Price + firstMid); while (true) { var mid = _lkoh.BestPair.SpreadPrice / 2; // если спред вышел за пределы нашего диапазона if (mid != null && ((firstMid + firstMid * delta) <= mid || (firstMid - firstMid * delta) >= mid) ) { var order = new Order { Portfolio = _portfolio, Price = _lkoh.ShrinkPrice(_lkoh.BestBid.Price + mid.Value), Security = _lkoh, Volume = 1, Direction = Sides.Buy, }; trader.RegisterOrder(order); Console.WriteLine(LocalizedStrings.Str1157Params, order.Id); break; } else { Console.WriteLine(LocalizedStrings.Str2176Params, _lkoh.BestBid.Price + mid); } // ждем 1 секунду Thread.Sleep(1000); } // останавливаем подключение trader.Disconnect(); } } } catch (Exception ex) { Console.WriteLine(ex); } }
private void StartClick(object sender, RoutedEventArgs e) { if (_strategy == null) { if (Portfolios.SelectedPortfolio == null) { MessageBox.Show(this, LocalizedStrings.Str3009); return; } // регистрируем наш тайм-фрейм var series = new CandleSeries(typeof(TimeFrameCandle), _lkoh, _timeFrame); // создаем торговую стратегию, скользящие средние на 80 5-минуток и 10 5-минуток _strategy = new SmaStrategy(_candleManager, series, new SimpleMovingAverage { Length = 80 }, new SimpleMovingAverage { Length = 10 }) { Volume = 1, Security = _lkoh, Portfolio = Portfolios.SelectedPortfolio, Connector = _trader, }; _strategy.Log += OnLog; _strategy.PropertyChanged += OnStrategyPropertyChanged; _candlesElem = new ChartCandleElement(); _area.Elements.Add(_candlesElem); _longMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Long, Color = Colors.OrangeRed }; _area.Elements.Add(_longMaElem); _shortMaElem = new ChartIndicatorElement { Title = LocalizedStrings.Short, Color = Colors.RoyalBlue }; _area.Elements.Add(_shortMaElem); IEnumerable <Candle> candles = CultureInfo.InvariantCulture.DoInCulture(() => File.ReadAllLines("LKOH_history.txt").Select(line => { var parts = line.Split(','); var time = (parts[0] + parts[1]).ToDateTime("yyyyMMddHHmmss").ApplyTimeZone(TimeHelper.Moscow); return((Candle) new TimeFrameCandle { OpenPrice = parts[2].To <decimal>(), HighPrice = parts[3].To <decimal>(), LowPrice = parts[4].To <decimal>(), ClosePrice = parts[5].To <decimal>(), TimeFrame = _timeFrame, OpenTime = time, CloseTime = time + _timeFrame, TotalVolume = parts[6].To <decimal>(), Security = _lkoh, State = CandleStates.Finished, }); }).ToArray()); var lastCandleTime = default(DateTimeOffset); // начинаем вычислять скользящие средние foreach (var candle in candles) { ProcessCandle(candle); lastCandleTime = candle.OpenTime; } _candleManager.Start(series); // вычисляем временные отрезки текущей свечи var bounds = _timeFrame.GetCandleBounds(_trader.CurrentTime); candles = _candleManager.Container.GetCandles(series, new Range <DateTimeOffset>(lastCandleTime + _timeFrame, bounds.Min)); foreach (var candle in candles) { ProcessCandle(candle); } _isTodaySmaDrawn = true; Report.IsEnabled = true; } if (_strategy.ProcessState == ProcessStates.Stopped) { // запускаем процесс получения стакана, необходимый для работы алгоритма котирования _trader.RegisterMarketDepth(_strategy.Security); _strategy.Start(); Start.Content = LocalizedStrings.Str242; } else { _trader.UnRegisterMarketDepth(_strategy.Security); _strategy.Stop(); Start.Content = LocalizedStrings.Str2421; } }
static void Main(string[] args) { var tradeBufferMax = 200; var depthBufferMax = 1000; var tradeBuffers = new Dictionary <string, List <Trade> >(); var depthBuffers = new Dictionary <string, List <MarketDepth> >(); var tradeStorages = new Dictionary <string, IMarketDataStorage <Trade> >(); var depthStorages = new Dictionary <string, IMarketDataStorage <MarketDepth> >(); List <string> securityIds = new List <string>(); StorageFormats storageFormat; string storagePath; var settings = XElement.Load("settings.xml"); storagePath = @settings.Element("storage-path").Value; storageFormat = (StorageFormats)Enum.Parse(typeof(StorageFormats), settings.Element("storage-format").Value.ToUpper()); foreach (var item in settings.Element("securities").Elements()) { var secId = item.Element("security").Value; securityIds.Add(secId); depthBuffers.Add(secId, new List <MarketDepth>()); tradeBuffers.Add(secId, new List <Trade>()); } var storage = new StorageRegistry() { DefaultDrive = new LocalMarketDataDrive { Path = storagePath } }; var connector = new QuikTrader(); // Ставим false, чтобы квик при старте не загрузил все 30 тыс инструментов connector.RequestAllSecurities = false; // Контролируем соединение в течение работы срочного рынка connector.ReConnectionSettings.WorkingTime = ExchangeBoard.Forts.WorkingTime; // Обработчик события успешного соединения connector.Connected += () => { Console.WriteLine("Соединение установлено!"); if (securityIds.Any()) { // Запрашиваем инструменты foreach (var id in securityIds) { connector.LookupSecurities(new Security() { Code = id.Split('@')[0], Board = ExchangeBoard.GetBoard(id.Split('@')[1]) }); } } else { Console.WriteLine("Нет инструментов для запроса!"); } }; connector.LookupSecuritiesResult += (ex, securities) => { foreach (var security in securities) { if (tradeStorages.ContainsKey(security.Id) || depthStorages.ContainsKey(security.Id)) { continue; } // Инициализируем специализированные хранилища tradeStorages.Add(security.Id, storage.GetTradeStorage(security, null, storageFormat)); depthStorages.Add(security.Id, storage.GetMarketDepthStorage(security, null, storageFormat)); // Региструем получение сделок if (!connector.RegisteredTrades.Contains(security)) { connector.RegisterTrades(security); } // Региструем получение стаканов if (!connector.RegisteredMarketDepths.Contains(security)) { connector.RegisterMarketDepth(security); } } }; connector.NewTrades += trades => { foreach (var trade in trades) { var secId = trade.Security.Id; tradeBuffers[secId].Add(trade); if (tradeBuffers[secId].Count >= tradeBufferMax) { var forsave = tradeBuffers[secId].TakeLast(tradeBufferMax); tradeBuffers[secId] = tradeBuffers[secId].Except(forsave).ToList(); var task = Task.Factory.StartNew(() => tradeStorages[secId].Save(forsave)); } } }; connector.MarketDepthsChanged += depths => { foreach (var depth in depths) { var secId = depth.Security.Id; depthBuffers[secId].Add(depth); if (depthBuffers[secId].Count >= depthBufferMax) { var forsave = depthBuffers[secId].TakeLast(depthBufferMax); depthBuffers[secId] = depthBuffers[secId].Except(forsave).ToList(); var task = Task.Factory.StartNew(() => depthStorages[secId].Save(forsave)); } } }; // Обработчик события разрыва соединения connector.Disconnected += () => Console.WriteLine("Соединение разорвано!"); // Команда соединения connector.Connect(); Console.Read(); var ttasks = new List <Task>(); var dtasks = new List <Task>(); foreach (var security in connector.Securities) { // Отменяем регистрацию сделок if (connector.RegisteredTrades.Contains(security)) { connector.UnRegisterTrades(security); } // Отменяем получение стаканов if (connector.RegisteredMarketDepths.Contains(security)) { connector.UnRegisterMarketDepth(security); } // Записываем остатки данных ttasks.Add(Task.Factory.StartNew(() => tradeStorages[security.Id].Save(tradeBuffers[security.Id]))); dtasks.Add(Task.Factory.StartNew(() => depthStorages[security.Id].Save(depthBuffers[security.Id]))); } Console.WriteLine("Записываем остатки данных!"); // Чуток ждем Task.WaitAll(ttasks.ToArray()); Task.WaitAll(dtasks.ToArray()); // Команда разрыва соединения connector.Disconnect(); }