Закрыть все позиции с котированием
Atom
27.11.2012


Пробую реализовывать простые сценарии на S#. Один из таких сценариев - закрытие всех позиций через стратегию котирования (какую именно - не принципиально, пусть будет LimitQuotingStrategy). По этому поводу написано нехитрое тестовое WPF приложение (текст приведен ниже).

Проблема заключается в том, что если раскомментировать строки 314-326 и 329 (т.е. создание стратегии для каждого инструмента и её запуск), то в обработчике события NewMarketDepths вылетает исключение:
Цитата:
An exception of type 'System.NullReferenceException' occurred in WPF stocksharp study.exe but was not handled in user code

Additional information: Ссылка на объект не указывает на экземпляр объекта.

If there is a handler for this exception, the program may be safely continued.


Экспериментально установил, что исключение связано с тем, что идет обращение к d.BestBid.Price (т.е. получение последней лучшей котировки).

Если оставить в приведенном коде всё как есть с комментариями, то стаканы для инструментов, по которым есть открытые позиции, стартуют отлично и в текстовом поле LogWindow цена лучшего бида появляется - т.е. обработчик события NewMarketDepths не падает из-за пустого указателя.

Что я делаю не так? Очевидно, я не учел какую-то очень важную особенность при работе с библиотекой. Но какую???

Версия библиотеки - 4.1.6.

PS: Если кто-то найдет что-либо полезное в моем примере - не возбраняется забрать на заметку с целью дальнейшего использования. :)

Код MainWindow.xaml:
Код
<?xml version="1.0" encoding="utf-8"?>
<Window
	x:Class="WPF_stocksharp_study.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d3="http://research.microsoft.com/DynamicDataDisplay/1.0"
    xmlns:Xaml="clr-namespace:StockSharp.Xaml;assembly=StockSharp.Xaml"
	Title="WPF_stocksharp_study"
    x:Name="mainWindow"
	ResizeMode="CanMinimize" Width="500" Height="520"
>
    <StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="5">
            <Label Content="Путь к QUIK:" HorizontalAlignment="Left" VerticalAlignment="Center" />
            <TextBox Name="Path" HorizontalAlignment="Left" VerticalAlignment="Center" Width="350" />
            <Button Name="LocateQuikButton" Content="..." HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="35" Margin="10,0,10,0" IsEnabled="True" Click="LocateQuikButton_Click" IsDefault="True" />
        </StackPanel>
        <StackPanel Margin="5">
            <StackPanel Orientation="Horizontal">
                <Button Name="ConnectButton" Content="Подключиться" Click="ConnectButton_Click" />
                <Button	Name="StartWatchSec1Sec2Button" Content="Включить экспорт инструментов" Click="StartWatchSec1Sec2Button_Click" IsEnabled="False" />
                <Button Name="ShowDepthsForPositionsButton" Content="Экспорт инструментов в позициях" Click="ShowDepthsForPositionsButton_Click" IsEnabled="False" />
            </StackPanel>
            <StackPanel Orientation="Horizontal">

            </StackPanel>
        </StackPanel>
        <Grid Margin="5" HorizontalAlignment="Left">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="100"/>
            </Grid.ColumnDefinitions>
            <Label Content="Инструмент 1" Grid.Column="0" Grid.Row="0" />
            <Label Content="Инструмент 2" Grid.Column="0" Grid.Row="1" />
            <ComboBox x:Name="Security1List" SelectionChanged="SecurityList_SelectionChanged" HorizontalAlignment="Stretch" Grid.Column="1" Grid.Row="0" IsEnabled="False" />
            <ComboBox x:Name="Security2List" SelectionChanged="SecurityList_SelectionChanged" HorizontalAlignment="Stretch" Grid.Column="1" Grid.Row="1" IsEnabled="False" />
        </Grid>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Left" Margin="5">
            <Label Content="Позиции:" />
            <ListView x:Name="MyPositions" Height="150" ItemsSource="{Binding}" FontSize="10" >
                <ListView.View>
                    <GridView>
                        <GridViewColumn Width="100" Header="Счет" DisplayMemberBinding="{Binding Path=Portfolio.Name}" />
                        <GridViewColumn Width="100" Header="Инструмент" DisplayMemberBinding="{Binding Path=Security.Code}" />
                        <GridViewColumn Width="100" Header="Позиция" DisplayMemberBinding="{Binding Path=CurrentValue}" />
                        <GridViewColumn Width="100" Header="Заблокировано" DisplayMemberBinding="{Binding Path=BlockedValue}" />
                    </GridView>
                </ListView.View>
            </ListView>
        </StackPanel>
        <StackPanel>
            <TextBox x:Name="LogWindow" IsReadOnly="True" VerticalScrollBarVisibility="Auto" VerticalContentAlignment="Top" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Height="166" TextWrapping="Wrap" />
        </StackPanel>
    </StackPanel>
</Window>


Код MainWindow.xaml.cs
Код
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Ecng.Xaml;
using Ecng.ComponentModel;
using Ecng.Collections;
using Ecng.Common;
using System.Linq;
using StockSharp.Algo.Strategies;
using StockSharp.Algo;
using StockSharp.Logging;
using StockSharp.Xaml;
using StockSharp.BusinessEntities;
using StockSharp.Quik;
using MessageBox = System.Windows.MessageBox;


namespace WPF_stocksharp_study
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public QuikTrader _trader;
        public ThreadSafeObservableCollection<Position> Positions = new ThreadSafeObservableCollection<Position>();
        public static MainWindow Instance { get; private set; }

        private bool _isConnected = false, _isDdeStarted = false, _isWatchingStarted = false, _isQuotesRegistered = false, _isPositionsRegistered = false;
        private Security sec1, sec2;
        private List<Strategy> _strategies = new List<Strategy>();

        private LogManager LogManager = new LogManager();

        public MainWindow()
        {
            InitializeComponent();

            MainWindow.Instance = this;
            this.DataContext = this;

            this.Path.Text = QuikTerminal.GetDefaultPath();
            MyPositions.DataContext = Positions;

            var consoleLogListener = new ConsoleLogListener();
            this.LogManager.Listeners.Add(consoleLogListener);
        }

        #region Routines
        void StartDDE()
        {
            WriteLogMessage("Запускается экспорт DDE");

            _trader.StartExport(new[]
			                    {
			                    	_trader.SecuritiesTable,
			                    	_trader.EquityPositionsTable,
			                    	_trader.EquityPortfoliosTable,
                                    _trader.OrdersTable,
                                    _trader.TradesTable,
                                    _trader.MyTradesTable
			                    });

            UpdateControls();
        }

        void StopDDE()
        {
            WriteLogMessage("Останавливается экспорт DDE");
            _trader.StopExport();
            UpdateControls();
        }

        void StartWatch()
        {
            this._isWatchingStarted = true;

            this.sec1 = (Security)Security1List.SelectedItem;
            this.sec2 = (Security)Security2List.SelectedItem;

            if (sec1 != null)
                this._trader.RegisterMarketDepth(this.sec1);
            if (sec2 != null)
                this._trader.RegisterMarketDepth(this.sec2);
            _isQuotesRegistered = true;

            UpdateControls();
        }

        void StopWatch()
        {
            if (_isQuotesRegistered)
            {
                this._trader.UnRegisterMarketDepth(this.sec1);
                this._trader.UnRegisterMarketDepth(this.sec2);
            }

            this._isWatchingStarted = false;
            UpdateControls();
        }

        void UpdateControls()
        {
            ConnectButton.Content = (_isConnected) ? "Отключить" : "Подключить";
            _isDdeStarted = _trader.IsExportStarted;
            StartWatchSec1Sec2Button.Content = (_isDdeStarted) ? "Выключить экспорт инструментов" : "Включить экспорт инструментов";
            StartWatchSec1Sec2Button.IsEnabled = (Security1List.SelectedItem != null) && (Security2List.SelectedItem != null);
            Security1List.IsEnabled = Security2List.IsEnabled = _isDdeStarted;
            ShowDepthsForPositionsButton.IsEnabled = _isPositionsRegistered;
        }


        void WriteLogMessage(string message)
        {
            var _dt = DateTime.Now;
            var str = _dt.ToString("yyyy-MM-dd HH:mm:ss.ffff - ") + message + "\n";

            LogWindow.AppendText(str);
            LogWindow.ScrollToEnd();
        }

        void CalculateAndUpdateBidAsk()
        {
            // TODO: Implement CalculateAndUpdateBidAsk
        }
        #endregion

        #region Event handlers
        #region Event handlers for UI elements
        void ConnectButton_Click(object sender, RoutedEventArgs e)
        {
            if (!_isConnected)
            {
                if (this.Path.Text.IsEmpty())
                    MessageBox.Show(this, "Путь к Quik не выбран");
                else
                {
                    WriteLogMessage("Начинаем подключение!");
                    if (this._trader == null)
                    {
                        this._trader = new QuikTrader(this.Path.Text);
                        this.LogManager.Sources.Add(_trader);

                        // Подписываемся на событие появления портфелей
                        this._trader.NewPortfolios += portfolios => this.GuiAsync(() =>
                                                                                  {
                                                                                      WriteLogMessage("Портфели появились!");
                                                                                  });

                        this._trader.PortfoliosChanged += portfolios => this.GuiAsync(() =>
                                                                                   {
                                                                                       WriteLogMessage("Портфели изменились!");
                                                                                       portfolios.ForEach(p => WriteLogMessage(p.Name));
                                                                                   });

                        // Подписываемся на событие появления инструментов
                        this._trader.NewSecurities += securities => this.GuiAsync(() =>
                                                                                  {
                                                                                      Security1List.ItemsSource = this._trader.Securities;
                                                                                      Security2List.ItemsSource = this._trader.Securities;

                                                                                      WriteLogMessage("Инструменты появились!");
                                                                                  });

                        this._trader.NewMarketDepths += depths => this.GuiAsync(() =>
                                                                                {
                                                                                    depths.ForEach(d =>
                                                                                    {
                                                                                        WriteLogMessage(string.Format("Появился стакан для инструмента {0}. Бид: {1}", d.Security.Code, d.BestBid.Price));
                                                                                    });
                                                                                });

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

                        // Подписываемся на событие подлючения
                        this._trader.Connected += () => this.GuiAsync(() =>
                                                                      {
                                                                          _isConnected = true;
                                                                          WriteLogMessage("QUIK подключен!");
                                                                          StartDDE();
                                                                          UpdateControls();
                                                                      });

                        //this._trader.NewPositions += positions => this.GuiAsync(() =>
                        //                                                {
                        //                                                    Positions.Clear();
                        //                                                    Positions.AddRange(_trader.Positions.Where(p => p.CurrentValue != 0));
                        //                                                });

                        this._trader.PositionsChanged += positions => this.GuiAsync(() =>
                                                                      {
                                                                          Positions.Clear();
                                                                          Positions.AddRange(_trader.Positions.Where(p => p.CurrentValue != 0));

                                                                          if (!_isPositionsRegistered)
                                                                          {
                                                                              _isPositionsRegistered = true;
                                                                              UpdateControls();
                                                                          }
                                                                      });

                        // Подписываемся на событие отключения
                        this._trader.Disconnected += () => this.GuiAsync(() =>
                                                                         {
                                                                             _isConnected = false;
                                                                             WriteLogMessage("QUIK отключен!");
                                                                             UpdateControls();
                                                                         });

                        this._trader.ConnectionError += (f) => this.GuiAsync(() =>
                                                                        {
                                                                            WriteLogMessage("Ошибка подключения. " + f.Message);
                                                                        });

                    }
                    // Подключаемся
                    this._trader.Connect();
                }
            }
            else
            {
                StopWatch();
                StopDDE();
                this._trader.Disconnect();

                _isConnected = false;
                UpdateControls();
            }
        }

        void LocateQuikButton_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new FolderBrowserDialog();

            if (!this.Path.Text.IsEmpty())
                dlg.SelectedPath = this.Path.Text;

            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.Path.Text = dlg.SelectedPath;
            }
        }


        void StartWatchSec1Sec2Button_Click(object sender, RoutedEventArgs e)
        {
            if (_isWatchingStarted)
                StopWatch();
            else
                StartWatch();
        }

        void SecurityList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            sec1 = (Security)Security1List.SelectedItem;
            sec2 = (Security)Security2List.SelectedItem;

            UpdateControls();
        }
        #endregion

        #region Event handlers for application shutdown
        protected override void OnClosing(CancelEventArgs e)
        {
            if (this._trader != null)
            {
                if (_isDdeStarted)
                    StopDDE();
                if (_isWatchingStarted)
                    StopWatch();

                this._trader.Dispose();
            }

            base.OnClosing(e);
        }

        protected override void OnClosed(EventArgs e)
        {
            System.Windows.Application.Current.Shutdown();
            base.OnClosed(e);
        }
        #endregion

        private void ShowDepthsForPositionsButton_Click(object sender, RoutedEventArgs e)
        {
            _trader.Positions.ForEach(p =>
                {
                    WriteLogMessage("Актив: " + p.Security.Code + " Позиция: " + p.CurrentValue);

                    var _volume = p.CurrentValue;

                    if (_volume != 0)
                    {
                        WriteLogMessage("Запускается экспорт стакана для" + p.Security.Code);
                        _trader.RegisterMarketDepth(p.Security);
                    }

                    //var _depth = _trader.GetMarketDepth(p.Security).Clone();

                    //var _close = new LimitQuotingStrategy(_volume > 0 ? OrderDirections.Sell : OrderDirections.Buy, _volume.Abs(), (_depth.BestAsk.Price + _depth.BestBid.Price) / 2)
                    // {
                    //     Trader = this._trader,
                    //     Security = p.Security,
                    //     Portfolio = p.Portfolio
                    // };

                    //this.LogManager.Sources.Add(_close);

                    //_strategies.Add(_close);
                });

            //_strategies.ForEach(s => s.Start());
        }
        #endregion
    }
}

Теги:


Спасибо:


Algonavt

Фотография
Дата: 27.11.2012
Ответить


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

Стало быть, перед тем, как создавать страегии котирования (или выставлять заявки), надо как-то дождаться прихода события о появлении стакана для всех инструментов. Как это сделать - почти придумал, если кому интересно - выложу по выполнении.

Велосипед, однако. :)
Спасибо:

vil

Фотография
Дата: 11.12.2012
Ответить


Прошу не бросать помидорами. Из меня программист вообще никакой.
Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ?
Спасибо:

Algonavt

Фотография
Дата: 17.12.2012
Ответить


Почти так и сделал. Реализовал такой код:
Код
public class DepthStarter
    {
        public bool WaitForMarketDepth(ITrader trader, Security security)
        {
            if (security == null)
                throw new ApplicationException("DepthSelector: security == null!");

            var _depthTrigger = false;

            ManualResetEventSlim manualResetEvent = new ManualResetEventSlim(false);
            Action<IEnumerable<MarketDepth>> onDepthsChanged = p =>
            {
                if (FindDepth(trader, security))
                    manualResetEvent.Set();
            };

            try
            {
                trader.NewMarketDepths += onDepthsChanged;
                trader.MarketDepthsChanged += onDepthsChanged;

                trader.RegisterMarketDepth(security);

                _depthTrigger = FindDepth(trader, security);
                if (!_depthTrigger)
                    _depthTrigger = manualResetEvent.Wait(TimeSpan.FromSeconds(10));

                return _depthTrigger;

                //return FindDepth(trader, security) || manualResetEvent.Wait(TimeSpan.FromSeconds(10));   // Это НЕ РАБОТАЕТ!! Оставлено, чтобы помнить, как делать не надо.
            }
            finally
            {
                trader.NewMarketDepths -= onDepthsChanged;
                trader.MarketDepthsChanged -= onDepthsChanged;
            }
        }

        private bool FindDepth(ITrader trader, Security security)
        {
            return trader.RegisteredMarketDepths.Contains(security) ? (security.BestBid != null) || (security.BestAsk != null) : false;
        }
    }
Спасибо:

VassilSanych

Фотография
Дата: 18.12.2012
Ответить


vil Перейти
Прошу не бросать помидорами. Из меня программист вообще никакой.
Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ?

Ничего не мешает.
Но проще просто подписаться на событие.
Чем короче методы, тем лучше.

Спасибо:

Algonavt

Фотография
Дата: 18.12.2012
Ответить


VassilSanych Перейти
vil Перейти
Прошу не бросать помидорами. Из меня программист вообще никакой.
Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ?

Ничего не мешает.
Но проще просто подписаться на событие.
Чем короче методы, тем лучше.



Собственно, идея состояла в том, чтобы к моменту, когда потребуется регистрировать заявки по инструменту, стакан уже был запущен. Тогда и ожидать ничего не придется. Запуск стакана - как правило разовая операция (при старте или перезагрузке робота), работа с заявками - многократная. Так что перед каждой заявкой проверять/стартовать стакан - некруто с точки зрения производительности, как я думаю.
Спасибо:

Игорь Бакулин

Фотография
Дата: 18.12.2012
Ответить


Algonavt Перейти


//var _depth = _trader.GetMarketDepth(p.Security).Clone();

//var _close = new LimitQuotingStrategy(_volume > 0 ? OrderDirections.Sell : OrderDirections.Buy, _volume.Abs(), (_depth.BestAsk.Price + _depth.BestBid.Price) / 2)
// {
// Trader = this._trader,
// Security = p.Security,
// Portfolio = p.Portfolio
// };




Попробуйте так.

Код


                    var _depth = _trader.GetMarketDepth(p.Security).Clone();

                    if (_depth != null)
                    {
                    var _close = new LimitQuotingStrategy(_volume > 0 ? OrderDirections.Sell : OrderDirections.Buy, _volume.Abs(), (_depth.BestAsk.Price + _depth.BestBid.Price) / 2)
                     {
                         Trader = this._trader,
                         Security = p.Security,
                         Portfolio = p.Portfolio
                     };
                     }


еще бывает полезно проверять на not null _depth.BestAsk и _depth.BestBid т.к. для получения этих данных системе требуется какое-то время.
А пока данные не подгружены эти значения равны null, т.е. не инициализированы.

Ну а если вам важно отрабатывать нажатие на кнопку ShowDepthsForPositionsButton когда уже точно стакан подгружен,
то можно так
в xaml пишем
ShowDepthsForPositionsButton.IsEnabled = false
т.е. делаем кнопку не активной.
а в строки 169-175 добавить
ShowDepthsForPositionsButton.IsEnabled = true;

Код


this._trader.NewMarketDepths += depths => this.GuiAsync(() =>
     {
       depths.ForEach(d =>
           {		    
               WriteLogMessage (string.Format ( "Появился стакан для инструмента {0}. Бид: {1}", d.Security.Code, d.BestBid.Price));
           });
       ShowDepthsForPositionsButton.IsEnabled = true;
     });
Спасибо:

Algonavt

Фотография
Дата: 18.12.2012
Ответить


Собственно, я перед тем, как создавать дочерние стратегии распродажи портфеля запускаю стаканы для всех инструментов. Дочерние стратегии я начинаю создавать только если все стаканы запустились. То есть, для каждого из инструментов, по которому есть ненулевая позиция, сперва создается стакан через метод DepthStarter.WaitForMarketDepth(ITrader trader, Security security).

По поводу проверки _depth.BestAsk и _depth.BestBid на != null - согласен, в "боевом" режиме это надо делать, т.к. в теории в стакане могут исчезнуть все биды или все аски (для наиболее ликвидных инструментов это, конечно, маловероятно, но тем не менее лучше страховаться) - в документации на стокшарп такой тип "экстремальных" случаев также упоминается как возможный и, след-но, подлежащий обработке. Просто в примере не стал его включать.

А вот по поводу "для получения этих данных системе требуется какое-то время" вопрос на самом деле очень интересный. Тут я хочу спросить у разработчиков библиотеки, как задумана в логике библиотеки обработка ситуаций, когда стакан запущен, но новые данные по стакану из трейдера ещё не прибежали. Полагаю, что в качестве BestPair (и, соответственно, BestBid и BestAsk) предоставляется последнее закешированное значение. Так ли это?
Спасибо:

VassilSanych

Фотография
Дата: 04.02.2013
Ответить


Какое-то странное поведение
Если подписаться на лог стратегии котирования
Код
2013/02/04 17:37:43.749|       |LQS_RIH3@RTS_SPBFUT00066|Стратегия запущена. [0,-1]. Позиция при старте 0.
2013/02/04 17:37:43.752|       |LQS_RIH3@RTS_SPBFUT00066|Котирование на Sell объема 1.
2013/02/04 17:37:43.753|       |LQS_RIH3@RTS_SPBFUT00066|Приостановка правил. _rulesSuspendCount 1.
2013/02/04 17:37:43.771|       |LQS_RIH3@RTS_SPBFUT00066|Возобновление правил. _rulesSuspendCount 0.
2013/02/04 17:37:43.779|       |LQS_RIH3@RTS_SPBFUT00066|Цена текущей NULL и лучшей 161120.
2013/02/04 17:37:43.779|       |LQS_RIH3@RTS_SPBFUT00066|Лучший бид 161110 и лучший аск 161130.
2013/02/04 17:37:43.786|       |LQS_RIH3@RTS_SPBFUT00066|Регистрация новой Limit (0x159ADC6) заявки на Sell с ценой 161120 и объемом 1. 
2013/02/04 17:37:44.121|Warning|LQS_RIH3@RTS_SPBFUT00066|Заявка 63437501 в процессе регистрации.
2013/02/04 17:37:44.123|       |LQS_RIH3@RTS_SPBFUT00066|Заявка 63437501 принята биржей.
2013/02/04 17:37:44.124|       |LQS_RIH3@RTS_SPBFUT00066|Сброс счетчика ошибок регистрации с 0 до нуля.
2013/02/04 17:37:44.127|       |QuikManager|316 Заявка 63437501/1981856709 Продажа Цена=161120 Объем=1 Сост=Active Бал=1
2013/02/04 17:37:48.768|       |QuikManager|768 Сделка 04.02.2013 17:37:48 82247758 161120 1 от заявки 63437501/1981856709 Продажа Цена=161120 Объем=1 Сост=Done Бал=0
2013/02/04 17:37:48.771|       |LQS_RIH3@RTS_SPBFUT00066|Новая Sell сделка 82247758 по цене 161120 на 1 заявки 63437501.
2013/02/04 17:37:48.770|       |QuikManager|316 Заявка 63437501/1981856709 Продажа Цена=161120 Объем=1 Сост=Done Бал=0
2013/02/04 17:37:48.772|       |LQS_RIH3@RTS_SPBFUT00066|Новая позиция: SPBFUT00066-RIH3@RTS=-1.
2013/02/04 17:37:48.773|       |LQS_RIH3@RTS_SPBFUT00066|Позиция изменилась на -1. Оставшийся объем 0.
2013/02/04 17:37:48.773|       |LQS_RIH3@RTS_SPBFUT00066|Заканчиваем котирование.
2013/02/04 17:37:48.773|       |LQS_RIH3@RTS_SPBFUT00066|Стратегия останавливается. [0,-1]. Позиция при старте -1.
2013/02/04 17:37:48.775|       |LQS_RIH3@RTS_SPBFUT00066|Правило 'Изменение стакана инструмента RIH3@RTS (0x2790E95)'. Приостановлено.
2013/02/04 17:37:48.775|       |LQS_RIH3@RTS_SPBFUT00066|Ожидание снятия всех активных заявок.
2013/02/04 17:37:48.780|       |LQS_RIH3@RTS_SPBFUT00066|Стратегия остановлена. [0,-1]. Позиция при старте -1.

Вроде нормально (QuikManager - мой класс, который ловит события шлюза).
А вот если не подписываться:
Код
2013/02/04 17:25:05.735|       |QuikManager|196 Заявка 62514036/1981813976 Покупка Цена=161230 Объем=1 Сост=Done Бал=1
2013/02/04 17:25:05.970|       |QuikManager|196 Заявка 62514036/1981813976 Покупка Цена=161230 Объем=1 Сост=Done Бал=1
2013/02/04 17:25:05.971|       |QuikManager|235 Заявка 62514037/1981814003 Покупка Цена=161230 Объем=1 Сост=Active Бал=1
2013/02/04 17:25:06.171|       |QuikManager|235 Заявка 62514037/1981814003 Покупка Цена=161230 Объем=1 Сост=Done Бал=1
2013/02/04 17:25:06.172|       |QuikManager|200 Заявка 62514038/1981814030 Покупка Цена=161230 Объем=1 Сост=Done Бал=0
2013/02/04 17:25:06.250|       |QuikManager|251 Сделка 04.02.2013 17:25:06 82246193 161230 1 от заявки 62514038/1981814030 Покупка Цена=161230 Объем=1 Сост=Done Бал=0
2013/02/04 17:25:06.250|       |QuikManager|200 Заявка 62514038/1981814030 Покупка Цена=161230 Объем=1 Сост=Done Бал=0
2013/02/04 17:25:06.326|Error  |QuikManager|Ошибка регистрации заявки: System.InvalidOperationException: Сервер для транзакции 'ACTION=MOVE_ORDERS; CLASSCODE=SPBFUT; SECCODE=RIH3; MODE=0; FIRST_ORDER_NUMBER=1981814030; FIRST_ORDER_NEW_PRICE=161230; FIRST_ORDER_NEW_QUANTITY=0; TRANS_ID=62514039;' вернул неправильное сообщение 'Не найдена активная заявка для перестановки' по передвинутым заявкам.

Позиция закрывается, а вот в процессе - косяки.

Спасибо:


Добавить файлы через драг-н-дроп, , или вставить из буфера обмена.

loading
clippy