← 戻る

Cобытия по изменению состояния ордеров приходят только в режиме эмуляции

S# 4.1.6 Работа с Quik. Брокер Уралсиб. В режиме RealTimeEmlationTrader ордера выставляются, и информация о их выполнении поступает в лог, strategy.PositionManager.Position показывает позицию.

Когда переключаюсь с эмулятора на реальный QuikTrader. Ордер выставляется, но похоже события изменения состояния не вызываются, соответственно strategy.PositionManager.Position показывает 0. Может кто подать идею, в какой стороне мне копать?

И при работе через эмулятор похоже часть событий не активируется по крайней мере NewMyTrade, но так как strategy.PositionManager.Position обновляется работать можно.

このトピックは参考になりましたか?

トピックを共有

コメント (14)

ログイン または アカウントを作成, コメントを残すにはログインまたは新規登録してください

VassilSanych
VassilSanych

kahuna: события изменения состояния не вызываются, На слух как-то плохо воспринимается.

kahuna
kahuna 著者

например событие strategy.OrderChanged.

И следующий код никогда не исполняется (то что внутри цикла foreach) хотя ордера выставляются.

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

          _trades.Trades.AddRange(myTrades);
        }
        foreach (var myTrade in myTrades)
        {
          var trade = myTrade.Trade;
          Status.Text = "Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}." + 
          System.Convert.ToString(trade.Id) + System.Convert.ToString(trade.Price) +
          System.Convert.ToString(trade.Security.Code) + 
          System.Convert.ToString(trade.Volume) + System.Convert.ToString(trade.Time);
         }
       });

такое впечатление что у меня событийная модель не работает.

Попробую сделать упрощеный тестовый примерчик.

VassilSanych
VassilSanych

kahuna: _strategy.Orders.Any(o => o == t.Order)) Не уверен, что NewMyTrades и _strategy ссылаются на одни и те же экземпляры объектов заявок в памяти.

kahuna
kahuna 著者

VassilSanych:

kahuna: _strategy.Orders.Any(o => o == t.Order)) Не уверен, что NewMyTrades и _strategy ссылаются на одни и те же экземпляры объектов заявок в памяти.

Откуда то срисовал. Поменял на _trader.Orders.Any(o => o == t.Order), но все равно результат тот же, так как само событие NewMyTrades не вызывается.

VassilSanych
VassilSanych

kahuna: И следующий код никогда не исполняется (то что внутри цикла foreach) хотя ордера выставляются. Попробуйте всё-таки вставить строчку логирования перед foreach. Возможно всё-таки косяк с фильтром. Говоря о заявке в памяти, я подразумевал, что, может быть, лучше проверять какие-нибудь скалярные свойства ордеров, а не ссылки на объекты.

kahuna
kahuna 著者

VassilSanych:

kahuna: И следующий код никогда не исполняется (то что внутри цикла foreach) хотя ордера выставляются. Попробуйте всё-таки вставить строчку логирования перед foreach. Возможно всё-таки косяк с фильтром. Говоря о заявке в памяти, я подразумевал, что, может быть, лучше проверять какие-нибудь скалярные свойства ордеров, а не ссылки на объекты.

Попробовал поставил, выполнение до цикла просто не доходит. Не вызывается совсем этот обработчик события NewMyTrades.

Moadip
Moadip

Когда переключаюсь с эмулятора на реальный QuikTrader. Что подразумевается под "переключением"? Как вы это делаете, опишите подробнее, желательно с примером кода.

kahuna
kahuna 著者

Когда переключаюсь с эмулятора на реальный QuikTrader. Что подразумевается под "переключением"? Как вы это делаете, опишите подробнее, желательно с примером кода. Если оставляю #define EMULATOR сделки совершаются и событие стратегии OrderChanged срабатывает в лог попадает сообщение "состояние ордера изменилось".
не показывает Status.Text = _strategy.ProcessState.ToString(); не показывает PnL.Content = _strategy.PnLManager.PnL; не показывает Slippage.Content = _strategy.SlippageManager.Slippage; показывает Position.Content = _strategy.PositionManager.Position; не показываетLatency.Content = _strategy.Latency;

Если на реальном Quik (снят комментарий с #undef EMULATOR) то сделки совершаются но событие OrderChanged не срабатывает. не показывает Status.Text = _strategy.ProcessState.ToString(); не показывает PnL.Content = _strategy.PnLManager.PnL; не показывает Slippage.Content = _strategy.SlippageManager.Slippage; не показывает Position.Content = _strategy.PositionManager.Position; не показывает Latency.Content = _strategy.Latency;

Основной код:


#define EMULATOR
//#undef EMULATOR

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
using MessageBox = System.Windows.MessageBox;
using System.Threading;
using System.Linq;
using System.Xml;
using Xceed.Wpf.Toolkit;

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

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

namespace tryBot1
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>

    public partial class MainWindow : Window
   {


        private ConfigFile CfgFile;

#if EMULATOR
        private RealTimeEmulationTrader<QuikTrader> _trader;
#else
        private QuikTrader _trader;
#endif

        public static MarketDepth _depth;
        private tryStrategy _strategy;
        private bool _isDdeStarted;
        private MonitorWindow monitor;
        private LogManager _logManager;

        public static bool tryBuy = false;
        public static bool trySell = false;



        public MainWindow()
        {

            InitializeComponent();

            CfgFile = new ConfigFile("c:\\tryBot1\\","config.cfg");
            monitor = new MonitorWindow();
            monitor.Show();
            _logManager = new LogManager();
            //var fileListener = new FileLogListener("{0}_{1:00}_{2:00}.txt".Put(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day));
            //logManager.Listeners.Add(fileListener);
            _logManager.Listeners.Add(new GuiLogListener(monitor));


        }

        private void Connect_Click(object sender, RoutedEventArgs e)
        {
            //устанвавливаем элемент ComboBox на значение по умолчанию
            //прочитанное ранее из config.cnf
            String DefSecurity = CfgFile.ReadParam("Security");
            String DefPortfolio = CfgFile.ReadParam("Portfolio");
            //КОНЕЦ- устанвавливаем элемент ComboBox на значение по умолчанию
            //прочитанное ранее из config.cnf
            int i = 0;
            if (_trader == null || !_trader.IsConnected)
            {
                if (_trader == null)
                {
                    if (QuikTerminal.GetDefaultPath().IsEmpty())
                    {
                        MessageBox.Show(this, "Путь к Quik не выбран.");
                        return;
                    }
                    Status.Text = "Connecting with Quck. Please wait";

                    #if EMULATOR
                        _trader = new RealTimeEmulationTrader<QuikTrader>(new QuikTrader(QuikTerminal.GetDefaultPath()));
                    #else
                        _trader = new QuikTrader(QuikTerminal.GetDefaultPath()){ IsAsyncMode = true, SupportManualOrders = false };
                        _trader.IsAsyncMode = true;
                    #endif

                        _trader.Connected += () =>
                         {


                             _trader.NewSecurities += securities => this.GuiAsync(() =>
                                {
                                    Securities1.ItemsSource = _trader.Securities;

                                    i = 0;
                                    foreach (Object item in Securities1.Items)
                                    {
                                        Securities1.SelectedIndex = i;
                                        if (item.ToString().Equals(DefSecurity))
                                        {
                                            break;
                                        }
                                        i++;
                                    }
                                    // если инструмент и стакан уже появились 
                                     if (Securities1.SelectedItem != null)
                                    {
                                        Status.Text = "Инструмент появился.";

                                    }

                                });
                             _trader.NewPortfolios += portfolios => this.GuiAsync(() =>
                                 {
                                     Portfolios.ItemsSource = _trader.Portfolios;

                                     i = 0;
                                     foreach (Object item in Portfolios.Items)
                                     {
                                         Portfolios.SelectedIndex = i;
                                         if (item.ToString().Equals(DefPortfolio))
                                         {
                                             break;
                                         }
                                         i++;
                                     }
                                 });

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

                                     //_trades.Trades.AddRange(myTrades);
                                 }
                                 foreach (var myTrade in myTrades)
                                 {
                                     var trade = myTrade.Trade;
                                     Status.Text = "Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}." + System.Convert.ToString(trade.Id) + System.Convert.ToString(trade.Price) +
                                     System.Convert.ToString(trade.Security.Code) + System.Convert.ToString(trade.Volume) + System.Convert.ToString(trade.Time);
                                 }
                             });
                             

                             // подписываемся на событие обновления стакана
                             _trader.MarketDepthsChanged += depths => this.GuiAsync(() =>
                             {
                                 if (_depth == null && Securities1.SelectedItem != null)
                                 {
                                     _depth = depths.FirstOrDefault(d => d.Security.Equals( (Security)Securities1.SelectedItem ));


                                     while (_depth == null) ;
                                           Status.Text = "Стакан появился.";
                                 }
                             });


                         };//КОНЕЦ _trader.Conected

                    _trader.ConnectionError += ex =>
                            {
                                if (ex != null)
                                    this.GuiAsync(() => MessageBox.Show(this, ex.ToString()));
                            };

                    this.GuiAsync(() =>
                            {
                                Connect.IsEnabled = false;
                                ExportDde.IsEnabled = true;
                                Report.IsEnabled = true;
                            });

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

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

                    // запускаем экспорт по DDE
                    _trader.Connect();

                    while (!_trader.IsConnected) { }
                    Status.Text = "Connected with Quik terminal";
                    StartDde();

                    #if EMULATOR
                    _trader.UnderlyingTrader.LogLevel = LogLevels.Debug;
                    _logManager.Sources.Add(_trader.UnderlyingTrader);
                    #else
                      _trader.LogLevel = LogLevels.Debug;
                      _logManager.Sources.Add(_trader);
                    #endif
                }
                else
                    _trader.Disconnect();
            }
        }

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

        private void StartDde()
		{
			_trader.StartExport();
			_isDdeStarted = true;
   		}

		private void StopDde()
		{
			_trader.StopExport();
			_isDdeStarted = false;
		}

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


        private void SwitchOn_Click(object sender, RoutedEventArgs e)
        {

            if (_strategy == null )
            {

                // создаем торговую стратегию, 
                _strategy = new tryStrategy()
                {
                    Volume = 1,     
                    Security = (Security)Securities1.SelectedItem,
                    Portfolio = (Portfolio)Portfolios.SelectedItem,
                    Trader = _trader
                };
                _strategy.PropertyChanged += OnStrategyPropertyChanged;
                _logManager.Sources.Add(_strategy);



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

        
        private void ExportDde_Click(object sender, RoutedEventArgs e)
        {
            if (_isDdeStarted)
				StopDde();
			else
				StartDde();
        }
        


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

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



        private void button2_Click(object sender, RoutedEventArgs e)
        {
            tryBuy = true;
            trySell = false;

        }

        private void button3_Click(object sender, RoutedEventArgs e)
        {
            tryBuy = false;
            trySell = true;           
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {


            base.OnClosing(e);
            if (_trader != null)
            {
                //_candleManager.Stop(_series);  //????????
                _trader.UnRegisterMarketDepth(_strategy.Security);
                _strategy.Stop();
                Status.Text = "Стоп";
                // останавливаем экспорт по DDE
                #if EMULATOR
                //ниже две сторчки для работы на эмуляторе
                    _trader.UnderlyingTrader.StopExport(new[] { _trader.UnderlyingTrader.SecuritiesTable, _trader.UnderlyingTrader.MyTradesTable, _trader.UnderlyingTrader.EquityPositionsTable,
                        _trader.UnderlyingTrader.EquityPortfoliosTable, _trader.UnderlyingTrader.OrdersTable });
                 #else
                    _trader.StopExport(new[] { _trader.SecuritiesTable, _trader.MyTradesTable, _trader.EquityPositionsTable,
                        _trader.EquityPortfoliosTable, _trader.OrdersTable });
                #endif

                if (_trader.IsConnected) _trader.Disconnect();
                //_trader.Dispose();

                CfgFile.WriteParam("Portfolio", Portfolios.SelectedItem.ToString());
                CfgFile.WriteParam("Security", Securities1.SelectedItem.ToString());

            }
            base.OnClosing(e);
        }

    }
}

Код стратегии (выставляет ордера по нажатии кнопок в форме ) :


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Ecng.Collections;
using Ecng.Common;
using StockSharp.Algo;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Indicators.Trend;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Logging;
using StockSharp.Quik;





namespace tryBot1
{


        /// <summary> 
        /// Стратегия для проверки работы коннектора. Ручной запуск трейдов по состоянию cтатических 
        /// переменных базового окна tryBuy или trySell, там они меняются кнопками.
        /// </summary> 
    public class tryStrategy :  Strategy //
        {
        private DateTime StartTime = DateTime.Now;
        private Order myOrder;
        public decimal _StopLoss = 200; //strategy stop loss
        public decimal _TakeProfit = 700; //strategy stop loss



        public tryStrategy() { }

		protected override void OnStarted()
		{

            Security
                .WhenChanged()
                .Do(TryMakeTrade).Apply(this); //когда меняется цена по инструменту проверяем "не выставить ли ордер"
            
            //следующие события должны бы выполняться но не выполняются с чем и боремся
            this.WhenNewMyTrades().Do(OnNewOrderTrades).Apply(this);
            this.WhenOrderChanged().Do( ()=>
                { 
                    this.write("состояние ордера изменилось");
                }).Apply(this);

            //это надо для того чтобы на фьючах рабтали заявки по рынку. 
            this.Security.MaxPrice = 1000000;
            this.Security.MinPrice = 0;

			base.OnStarted();
		}



         /// <summary>
        /// проверяем условия и пытаемся выполнить трейд
        /// </summary>
        /// <param name="candle"></param>
        private void TryMakeTrade()
        {

            // если наша стратегия в процессе остановки
            if (ProcessState == ProcessStates.Stopping)
            {
                // отменяем активные заявки
                CancelActiveOrders();
                return;
            }


            if (tryBot1.MainWindow._depth != null)
            {

                if ( tryBot1.MainWindow.tryBuy )
                {
                    //отменяем все несработавшие
                        foreach (Strategy s in this.ChildStrategies)
                        {
                            s.CancelActiveOrders();
                        }
                        this.CancelActiveOrders();

                    this.write("buy Volume=" + Volume.ToString());
                    decimal _price = Security.BestAsk.Price + Security.MinStepSize;
                    myOrder = this.CreateOrder(OrderDirections.Buy, _price, Volume);
                    RegisterOrder(myOrder);
                    tryBot1.MainWindow.tryBuy = false;
                }
                if (tryBot1.MainWindow.trySell)
                {
                    //отменяем все несработавшие
                        foreach (Strategy s in this.ChildStrategies)
                        {
                            s.CancelActiveOrders();
                        }
                        this.CancelActiveOrders();

                    this.write("sell Volume=" + Volume.ToString());
                    decimal _price = Security.BestBid.Price - Security.MinStepSize;
                    myOrder = this.CreateOrder(OrderDirections.Sell, _price, Volume);
                    RegisterOrder(myOrder);
                    tryBot1.MainWindow.trySell = false;
                }

                foreach (Strategy s in this.ChildStrategies)
                {
                    s.Security.MaxPrice = 1000000;
                    s.Security.MinPrice = 0;
                }
            } //end if __depth
        }


        private void OnNewOrderTrades(IEnumerable<MyTrade> trades)
        {
            this.write("новый трейд");
            /*
            // для каждой сделки добавляем защитную пару стратегии 
            var protectiveStrategies = trades.Select(t =>
            {
                // выставляет тейк-профит в 40 пунктов 
                var takeProfit = new TakeProfitStrategy(t, _TakeProfit);

                // выставляет стоп-лосс в 20 пунктов 
                var stopLoss = new StopLossStrategy(t, _StopLoss);
                return new TakeProfitStopLossStrategy(takeProfit, stopLoss);
            });
            protectiveStrategies.ForEach( strategy => this.ChildStrategies.Add(strategy) );
            */
        }


        /*
        override protected void OnNewMyTrades(IEnumerable<MyTrade> trades)
        {
            foreach(MyTrade trd in trades)
            {
            this.write("Trade time=" + trd.Trade.Time);
            }

            //aprotect.ProcessNewMyTrades(trades);
            base.OnNewMyTrades(trades);
        }*/

        public void write(String mes)
        {
            LogMessage logMessage = new LogMessage(this, DateTime.Now, LogLevels.Info, mes);
            RaiseLog(logMessage);
        }
 
    }
}


Moadip
Moadip

Несколько замечаний по коду.

Если оставляю #define EMULATOR сделки совершаются и событие стратегии OrderChanged срабатывает в лог попадает сообщение "состояние ордера изменилось". Если на реальном Quik (снят комментарий с #undef EMULATOR) то сделки совершаются но событие OrderChanged не срабатывает. Как то сложно, да и лениво каждый раз комментить/раскомментить директивы препроцессора. Объявите поле _trader типа ITrader.


private ITrader _trader;

Добавьте на форму ComboBox с двумя Item. Что нибудь типа:


<ComboBox Name="cmbTrader" >
	<ComboBoxItem Content="Эмуляция" />
	<ComboBoxItem Content="Реал" />
</ComboBox>

И потом в коде, в зависимости от того что выбранно создавать или QuikTrader или RTET<QuikTrader>


//Выбор шлюза
switch (cmbTrader.SelectedIndex)
{
	case 0:
		_trader= new RealTimeEmulationTrader<QuikTrader>(new QuikTrader(QuikTerminal.GetDefaultPath()));
		break;

	case 1:
		_trader = new QuikTrader(QuikTerminal.GetDefaultPath())
		break;
}

Рекомендую прочитать серию статей от FinDirector, почерпнете для себя много интересного.


_trader = new QuikTrader(QuikTerminal.GetDefaultPath()){ IsAsyncMode = true, SupportManualOrders = false };
_trader.IsAsyncMode = true;

В инициализаторе уже задано значение св-ва IsAsyncMode, нет смысла делать это еще раз.


 Status.Text = "Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}." + System.Convert.ToString(trade.Id) + System.Convert.ToString(trade.Price) +
 System.Convert.ToString(trade.Security.Code) + System.Convert.ToString(trade.Volume) + System.Convert.ToString(trade.Time);

Можно заменить на


Status.Text = "Сделка {Id} по цене {Price} по бумаге {Security.Code} по объему {Volume} в {Time}.".PutEx(trade)

Запуск/остановка экспорта


        private void StartDde()
        {
            _trader.StartExport();
            _isDdeStarted = true;
        }
 
        private void StopDde()
        {
            _trader.StopExport();
            _isDdeStarted = false;
        }

Если на экспорт запускаются все таблицы StartExport(), то нет смысла потом перечислять какие именно надо таблицы остановить.


                //ниже две сторчки для работы на эмуляторе
                    _trader.UnderlyingTrader.StopExport(new[] { _trader.UnderlyingTrader.SecuritiesTable, _trader.UnderlyingTrader.MyTradesTable, _trader.UnderlyingTrader.EquityPositionsTable,
                        _trader.UnderlyingTrader.EquityPortfoliosTable, _trader.UnderlyingTrader.OrdersTable });
                 #else
                    _trader.StopExport(new[] { _trader.SecuritiesTable, _trader.MyTradesTable, _trader.EquityPositionsTable,
                        _trader.EquityPortfoliosTable, _trader.OrdersTable });
                #endif

Проще вызвать StopDde() или напрямую _trader.StopExport();


        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
 
 
            base.OnClosing(e);
            if (_trader != null)
            {
                //_candleManager.Stop(_series);  //????????
                _trader.UnRegisterMarketDepth(_strategy.Security);
                _strategy.Stop();
                Status.Text = "Стоп";
                // останавливаем экспорт по DDE
                #if EMULATOR
                //ниже две сторчки для работы на эмуляторе
                    _trader.UnderlyingTrader.StopExport(new[] { _trader.UnderlyingTrader.SecuritiesTable, _trader.UnderlyingTrader.MyTradesTable, _trader.UnderlyingTrader.EquityPositionsTable,
                        _trader.UnderlyingTrader.EquityPortfoliosTable, _trader.UnderlyingTrader.OrdersTable });
                 #else
                    _trader.StopExport(new[] { _trader.SecuritiesTable, _trader.MyTradesTable, _trader.EquityPositionsTable,
                        _trader.EquityPortfoliosTable, _trader.OrdersTable });
                #endif
 
                if (_trader.IsConnected) _trader.Disconnect();
                //_trader.Dispose();
 
                CfgFile.WriteParam("Portfolio", Portfolios.SelectedItem.ToString());
                CfgFile.WriteParam("Security", Securities1.SelectedItem.ToString());
 
            }
            base.OnClosing(e);
        }

Дублируется base.OnClosing(e); Не смертельно, но все же.


            //это надо для того чтобы на фьючах рабтали заявки по рынку.
            this.Security.MaxPrice = 1000000;
            this.Security.MinPrice = 0;

Сначала подумал что в этом причина почему не срабатывает событие NewMyTrade, т.к. не совершается сделка. По идее не должно работать. Должно прийти сообщение об ошибке, что то типа цена ордера вне диапазона. Чтобы были цены планок лучше добавить соответствующие колонки в квик таблице "Инструменты" и потом добавить их в коде. Экспорт доп. колонок

Потом увидел что ценник выставляется по другому

_price = Security.BestBid.Price - Security.MinStepSize;

И методы BuyAtmarket и SellAtMarket не используются. Да и вы пишете что сделки совершаются.

Тогда не понятно в чем может быть причина.

Попробуйте максимально упростить код, чтобы проверить отрабатывает ли событие NewMyTrade. Один шлюз, минимум кода в стратегии. Попробуйте на последней сборке с codeplex, возможно причина в S#.

kahuna
kahuna
kahuna 著者

Попробуйте максимально упростить код, чтобы проверить отрабатывает ли событие NewMyTrade. Один шлюз, минимум кода в стратегии. Попробуйте на последней сборке с codeplex, возможно причина в S#. Попробовл без изменения кода перейти на 4.1.8 , стало еще веселее, теперь Positions не показывается и в режиме эмулятора. То есть событие OrderChanged тоже не прилетает. Verifier про настройку Quik говорит - все в порядке. Упростил код. Дальше уже кажется некуда. Картина сохранилась. 🤨 основной:



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
using MessageBox = System.Windows.MessageBox;
using System.Threading;
using System.Linq;
using System.Xml;
using Xceed.Wpf.Toolkit;

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

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

namespace test
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>

    public partial class MainWindow : Window
   {




        private RealTimeEmulationTrader<QuikTrader> _trader;
        //private QuikTrader _trader;


        public static MarketDepth _depth;
        private tryStrategy _strategy;
        private MonitorWindow monitor;
        private LogManager _logManager;
        private String DefSecurity = "RIH3@RTS";
        private String DefPortfolio = "SPBFUTXXXX";


        public static bool tryBuy = false;
        public static bool trySell = false;



        public MainWindow()
        {

            InitializeComponent();

            monitor = new MonitorWindow();
            monitor.Show();
            _logManager = new LogManager();
            //var fileListener = new FileLogListener("{0}_{1:00}_{2:00}.txt".Put(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day));
            //logManager.Listeners.Add(fileListener);
            _logManager.Listeners.Add(new GuiLogListener(monitor));


        }

        private void Connect_Click(object sender, RoutedEventArgs e)
        {


            if (_trader == null || !_trader.IsConnected)
            {
                if (_trader == null)
                {
                    if (QuikTerminal.GetDefaultPath().IsEmpty())
                    {
                        MessageBox.Show(this, "Путь к Quik не выбран.");
                        return;
                    }
                    Status.Text = "Connecting with Quck. Please wait";

                    _trader = new RealTimeEmulationTrader<QuikTrader>(new QuikTrader(QuikTerminal.GetDefaultPath()) { IsAsyncMode = true, SupportManualOrders = false });
                     //   _trader = new QuikTrader(QuikTerminal.GetDefaultPath()){ IsAsyncMode = true, SupportManualOrders = false };


                        _trader.Connected += () =>
                         {

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

                                 int i = 0;
                                 foreach (Object item in Securities1.Items)
                                 {
                                     Securities1.SelectedIndex = i;
                                     if (item.ToString().Equals(DefSecurity))
                                     {
                                         break;
                                     }
                                     i++;
                                 }
                                 // если инструмент и стакан уже появились 
                                 if (Securities1.SelectedItem != null)
                                 {
                                    Status.Text = "Инструмент появился.";
                                 }

                             });
                             _trader.NewPortfolios += portfolios => this.GuiAsync(() =>
                             {
                                 Portfolios.ItemsSource = _trader.Portfolios;

                                 int i = 0;
                                 foreach (Object item in Portfolios.Items)
                                 {
                                     Portfolios.SelectedIndex = i;
                                     if (item.ToString().Equals(DefPortfolio))
                                     {
                                         break;
                                     }
                                     i++;
                                 }
                             });


                             // подписываемся на событие появления моих новых сделок
                             _trader.NewMyTrades += myTrades => this.GuiAsync(() =>
                             {
                                 if (_strategy != null)
                                 {
                                     // найти те сделки, которые совершила стратегия 
                                     //myTrades = myTrades.Where(t => _strategy.Orders.Any(o => o == t.Order));
                                     myTrades = myTrades.Where(t => _trader.Orders.Any(o => o == t.Order));
                                 }
                                 foreach (var myTrade in myTrades)
                                 {
                                    var trade = myTrade.Trade;
                                    Status.Text = "Сделка {Id} по цене {Price} по бумаге {Security.Code} по объему {Volume} в {Time}.".PutEx(trade);
                                 }
                             });
                             

                             // подписываемся на событие обновления стакана
                             _trader.MarketDepthsChanged += depths => this.GuiAsync(() =>
                             {
                                 if (_depth == null && DefSecurity != null)
                                 {
                                     _depth = depths.FirstOrDefault(d => d.Security.Equals( (Security) this.Securities1.SelectedItem ));
                                     while (_depth == null) ;
                                         Status.Text = "Стакан появился.";
                                 }
                             });


                         };//КОНЕЦ _trader.Conected

                    _trader.ConnectionError += ex =>
                            {
                                if (ex != null)
                                    this.GuiAsync(() => MessageBox.Show(this, ex.ToString()));
                            };

                    this.GuiAsync(() =>
                            {
                                Connect.IsEnabled = false;
                                Report.IsEnabled = true;
                            });

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

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

                    // запускаем экспорт по DDE
                    _trader.Connect();
                    

                    while (!_trader.IsConnected) { }
                    Status.Text = "Connected with Quik terminal";
                    StartDde();

                    #if EMULATOR
                        _trader.UnderlyingTrader.LogLevel = LogLevels.Debug;
                        _logManager.Sources.Add(_trader.UnderlyingTrader);
                    #else
                        _trader.LogLevel = LogLevels.Debug;
                        _logManager.Sources.Add(_trader);
                    #endif
                }
                else
                    _trader.Disconnect();
            }
        }

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

        private void StartDde()
		{
			_trader.StartExport();
   		}

	private void StopDde()
		{
			_trader.StopExport();
		}

        private void OnStrategyPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
            _trader.AddInfoLog("OnStrategyPropertyChanged");
			this.GuiAsync(() =>
			{
				//Status.Content = _strategy.ProcessState;
                Status.Text = _strategy.ProcessState.ToString();
                PnL.Content = _strategy.PnLManager.PnL;
                Slippage.Content = _strategy.SlippageManager.Slippage;
				Position.Content = _strategy.PositionManager.Position;
                Latency.Content = _strategy.Latency;
			});
		}


        private void SwitchOn_Click(object sender, RoutedEventArgs e)
        {

            if (_strategy == null )
            {

                // создаем торговую стратегию, 
                _strategy = new tryStrategy()
                {
                    Volume = 1,     
                    Security = (Security)this.Securities1.SelectedItem,
                    Portfolio = (Portfolio)this.Portfolios.SelectedItem,
                    Trader = _trader
                };
                _strategy.PropertyChanged += OnStrategyPropertyChanged;
                _logManager.Sources.Add(_strategy);



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

        

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

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



        private void button2_Click(object sender, RoutedEventArgs e)
        {
            tryBuy = true;
            trySell = false;

        }

        private void button3_Click(object sender, RoutedEventArgs e)
        {
            tryBuy = false;
            trySell = true;           
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {


            if (_trader != null)
            {
                _trader.UnRegisterMarketDepth(_strategy.Security);
                _strategy.Stop();
                Status.Text = "Стоп";
                // останавливаем экспорт по DDE
                StopDde();

                if (_trader.IsConnected) _trader.Disconnect();
                //_trader.Dispose();

            }
            base.OnClosing(e);
        }

    }
}


для стратегии:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Ecng.Collections;
using Ecng.Common;
using StockSharp.Algo;
using StockSharp.Algo.Candles;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Indicators.Trend;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Logging;
using StockSharp.Quik;





namespace test
{


        /// <summary> 
        /// Стратегия для проверки работы коннектора. Ручной запуск трейдов по состоянию cтатических 
        /// переменных базового окна tryBuy или trySell, там они меняются кнопками.
        /// </summary> 
    public class tryStrategy :  Strategy //
        {
        private Order myOrder;

        public tryStrategy() { }

		protected override void OnStarted()
		{

            Security
                .WhenChanged()
                .Do(TryMakeTrade).Apply(this); //когда меняется цена по инструменту проверяем "не выставить ли ордер"
            
            //следующие события должны бы выполняться но не выполняются с чем и боремся
            this.WhenNewMyTrades().Do(OnNewOrderTrades).Apply(this);
            this.WhenOrderChanged().Do( ()=>
                { 
                    this.write("состояние ордера изменилось");
                }).Apply(this);
            this.WhenError().Do(() =>
            {
                this.write("прилетела ошибка");
            }).Apply(this);

            this.WhenOrderRegistered().Do(() =>
            {
                this.write("зарегистрирован ордер");
            }).Apply(this);

            this.WhenPnLChanged().Do(() =>
            {
                this.write("профит.лосс сменился");
            }).Apply(this);
            this.WhenWarning().Do(() =>
            {
                this.write("желтая карточка");
            }).Apply(this);

			base.OnStarted();
		}



         /// <summary>
        /// проверяем условия и пытаемся выполнить трейд
        /// </summary>
        /// <param name="candle"></param>
        private void TryMakeTrade()
        {

            // если наша стратегия в процессе остановки
            if (ProcessState == ProcessStates.Stopping)
            {
                // отменяем активные заявки
                CancelActiveOrders();
                return;
            }


            if (test.MainWindow._depth != null) //стакан работает?
            {

                if ( test.MainWindow.tryBuy )
                {
                    this.write("buy Volume=" + Volume.ToString());
                    decimal _price = Security.BestAsk.Price + Security.MinStepSize;
                    myOrder = this.CreateOrder(OrderDirections.Buy, _price, Volume);
                    RegisterOrder(myOrder);
                    test.MainWindow.tryBuy = false;
                }
                if (test.MainWindow.trySell)
                {
                    this.write("sell Volume=" + Volume.ToString());
                    decimal _price = Security.BestBid.Price - Security.MinStepSize;
                    myOrder = this.CreateOrder(OrderDirections.Sell, _price, Volume);
                    RegisterOrder(myOrder);
                    test.MainWindow.trySell = false;
                }


            } //end if __depth
        }


        private void OnNewOrderTrades(IEnumerable<MyTrade> trades)
        {
            this.write("новый трейд");
        }


        public void write(String mes)
        {
            LogMessage logMessage = new LogMessage(this, DateTime.Now, LogLevels.Info, mes);
            RaiseLog(logMessage);
        }
 
    }
}


kahuna
kahuna 著者

Может это как то проясняет дело. Простейший код в котором просто соединение с Quik выдает страную ошибку про какой-то инструмент😳



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Diagnostics;
using MessageBox = System.Windows.MessageBox;
using System.Threading;
using System.Linq;
using System.Xml;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Xaml;
using Ecng.ComponentModel;

using StockSharp.BusinessEntities;
using StockSharp.Algo.Reporting;
using StockSharp.Quik;
using StockSharp.Algo;
using StockSharp.Xaml;
using StockSharp.Logging;
using StockSharp.Algo.Testing;

namespace test
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>

    public partial class MainWindow : Window
   {
        private QuikTrader _trader;
        private LogManager _logManager;

        public MainWindow()
        {
            InitializeComponent();

            _logManager = new LogManager();
            var fileListener = new FileLogListener("{0}_{1:00}_{2:00}.txt".Put(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day));
            _logManager.Listeners.Add(fileListener);

            _trader = new QuikTrader(QuikTerminal.GetDefaultPath()){ IsAsyncMode = true, SupportManualOrders = false };

            _trader.LogLevel = LogLevels.Debug;
            _logManager.Sources.Add(_trader);

                    _trader.Connected += () =>
                     {
                         _trader.AddDebugLog("Соединились");
                     };

                    _trader.Connect();
                    

                    while (!_trader.IsConnected) { }
                    _trader.StartExport();
  
        }
    }
}

Ошибка в лог валится такая:2013/02/26 14:43:51.544|Debug |QuikTrader|Соединились 2013/02/26 14:43:53.367|Error |QuikTrader|System.InvalidOperationException: Инструмент с кодом RU000A0JPWC3 для бумажной позиции не найден. в StockSharp.Quik.QuikTrader.#=qjrOBFov$lIae$ZMCQLx7P1fQAe2X2s16$DxZRnv$aqU=.#=qjGe1xZF5fvarq_$jrR3XCQ==(IList1 #=qKG6nGjj9uhl1Ndb5IDukAw==, Func2 #=qdrbWxV4uORvFCQd5d$c6og==) в #=qU8C8kAMUmJ0kPIeEJrF68f3NMymXDukMNgL4Dc7ffmr7PRgVzknJ3atY_n0PucT4.#=qB09_IBYvsxLb_dLzMi2NWQ==(DdeTable #=qOgXoydWCvsq2gXlddKoo0w==, IList1 #=qMeYWUEb44NrXcAvbPuNfiQ==, Action2 #=qolGBgTssErk3vXo538xxsQ==, Action`1 #=qIfmNdbFGgLtG9ybpXuosbQ==, Boolean #=qe3W9$GyIKMHUi59wvLuQeA==) 2013/02/26 14:43:53.441| |QuikTrader|Экспорт запущен. Мистика. 🤬

kahuna
kahuna 著者

Понял, сам дурак. Просто давно завис в облигациях РБК. Валяются в портфеле. А в таблицах (сделок, заявок и т.п) облигации отфильтрованы.

kahuna
kahuna 著者

Включил фильтр на таблицу позиции по бумагам. Оставил одни фьючи. Ура. Все заработало. События на которые жаловался стали прилетать.

VassilSanych
VassilSanych

Похоже у вас не логируются исключения фоновых потоков. Это можно делать например так:

<Application x:Class="Robot.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml" Startup="Application_Startup_1"
						 DispatcherUnhandledException="Application_DispatcherUnhandledException" Exit="Application_Exit_1" >
    <Application.Resources>
         
    </Application.Resources>
</Application>
using System;
using System.Globalization;
using System.Security.Principal;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using Ecng.Collections;
using StockSharp.Logging;
using StockSharp.Xaml;

namespace Robot
{
	/// <summary>
	/// Interaction logic for App.xaml
	/// </summary>
	public partial class App : ILogReceiver
	{
		private void CurrentDomain_UnhandledException
			(object sender, UnhandledExceptionEventArgs e)
		{
			var ex = (Exception) e.ExceptionObject;
			this.AddErrorLog(ex.ToString());

			if (Current == null) return;
			if (
				Current.Dispatcher.Invoke(() => MessageBox.Show(
					ex.ToString(), "Ошибка",
					MessageBoxButton.OKCancel, MessageBoxImage.Error) == MessageBoxResult.Cancel)
				)
				Current.Shutdown();
		}

		private void Application_Startup_1(object sender, StartupEventArgs e)
		{
			AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

			LogManager = new LogManager();
			LogManager.Sources.Add(this);

			var fileListener = new FileLogListener(
				string.Format(CultureInfo.InvariantCulture, "{0:yyyyMMdd}.txt", DateTime.Today));
			fileListener.Append = true;
			LogManager.Listeners.Add(fileListener);

			this.AddInfoLog("Запуск UI робота");

			//if (!string.IsNullOrEmpty(Settings.GoogleLogin))
			//{
			//		var smsListener = new SmsLogListener(Settings.GoogleLogin, Settings.GooglePassword);
			//		smsListener.Filters.Add(LogListener.AllErrorFilter);
			//		LogManager.Listeners.Add(smsListener);
			//}


			//Monitor = new MonitorWindow();
			//Monitor.Show();
			//LogManager.Listeners.Add(new GuiLogListener(Monitor));

			CheckAdministrator();

		}

		public static LogManager LogManager { get; private set; }
		public static MonitorWindow Monitor { get; private set; }


		private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
		{
			var ex = e.Exception;
			this.AddErrorLog(ex.ToString());
			e.Handled = true;

			if (Current == null) return;
			if (
				Current.Dispatcher.Invoke(() => MessageBox.Show(
					ex.ToString(), "Ошибка",
					MessageBoxButton.OKCancel, MessageBoxImage.Error) == MessageBoxResult.Cancel)
				)
				Current.Shutdown();
		}

		#region ILogReceiver

		public DateTime CurrentTime
		{
			get { return LoggingHelper.Now; }
		}

		public INotifyList<ILogSource> Childs
		{
			get { return null; }
		}

		private readonly Guid _id = Guid.NewGuid();

		public Guid Id
		{
			get { return _id; }
		}

		public event Action<LogMessage> Log;

		public string Name
		{
			get { return ToString(); }
		}

		public ILogSource Parent
		{
			get { return null; }
		}

		public LogLevels LogLevel
		{
			get { return LogLevels.Debug; }
			set { }
		}

		public void Dispose()
		{
		}

		private void RaiseLog(LogMessage logMessage)
		{
			if (Log != null)
				Log(logMessage);
		}

		public void AddLog(LogMessage logMessage)
		{
			RaiseLog(logMessage);
		}

		#endregion

		private void CheckAdministrator()
		{
			var identity = WindowsIdentity.GetCurrent();
			if (identity == null) throw new InvalidOperationException("Couldn't get the current user identity");
			var principal = new WindowsPrincipal(identity);

			// Check if this user has the Administrator role. If they do, return immediately.
			// If UAC is on, and the process is not elevated, then this will actually return false.
			var isBuiltInAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);

			if (!isBuiltInAdmin)
			{
				var exMessage = "Робот запущен не под Администратором";
				this.AddErrorLog(exMessage);
				MessageBox.Show(
					exMessage, "Ошибка",
					MessageBoxButton.OK, MessageBoxImage.Error);
				Shutdown();
			}
		}

		private void Application_Exit_1(object sender, ExitEventArgs e)
		{
			this.AddInfoLog("Выключение UI робота");
			Thread.Sleep(500);
		}
	}
kahuna