Пример #1
0
        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);
            }
        }
Пример #2
0
        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;
            }
        }
Пример #3
0
        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();
        }