← Назад

Непонятки с MarketQuotingStrategy

Может кто подсказать как разобраться с проблемой? Вчера обнаружил что MQS в каких-то случаях выполняет задачу в двойном размере. Я завел топик и выложил там более полное описание, возможно, что название не совсем корректное. Сегодня на другом инструменте столкнулся опять с той же самой проблемой. Судя по журналу MQS пытается переставить заявку в данном случае 42133045, а она к этому моменту уже выполнена. Причем получив ошибку "Вы не можете снять данную заявку" выставляет новую заявку.

13:13:01.880 | | MQS | Перекотирование зарегистрировано для заявки 42133045на Buy с ценой 30295 объемом 1. 13:13:02.145 | Error | MQS | Заявка 42133045 не была принята по причине System.InvalidOperationException: Сервер для транзакции 'ACTION=MOVE_ORDERS; TRANS_ID=42133045; CLASSCODE=SPBFUT; SECCODE=SiH2; MODE=0; FIRST_ORDER_NUMBER=0; FIRST_ORDER_NEW_PRICE=30295; FIRST_ORDER_NEW_QUANTITY=1;' вернул неправильное сообщение 'Вы не можете снять данную заявку' по передвинутым заявкам.. 13:13:02.176 | Error | MQS | Заявка 42133045 не принята биржей по причине 'Сервер для транзакции 'ACTION=MOVE_ORDERS; TRANS_ID=42133045; CLASSCODE=SPBFUT; SECCODE=SiH2; MODE=0; FIRST_ORDER_NUMBER=0; FIRST_ORDER_NEW_PRICE=30295; FIRST_ORDER_NEW_QUANTITY=1;' вернул неправильное сообщение 'Вы не можете снять данную заявку' по передвинутым заявкам.'. 13:13:02.239 | | MQS | Цена текущей NULL и лучшей 30295. 13:13:02.301 | | MQS | Лучший бид 30295 и лучший аск 30297. 13:13:02.411 | | MQS | Регистрация новой заявки на Buy с ценой 30295 и объемом 1.

ps: если можно взглянуть на фрагмент MarketQuotingStrategy, который выполняет действия в приложенном логе, попытаюсь сам найти ответ

Комментарии (25)

Вход или Создать аккаунт, Войдите или зарегистрируйтесь, чтобы оставить комментарий

ak
ak

Столкнулся с такой же проблемой дважды причем подряд (QuikTrader, 4.0.17).


var takeProfit = new TakeProfitStrategy(trade, this.TakeProfitUnit) { UseQuoting = true };
var stopLoss = new StopLossStrategy(trade, StopLossUnit) { UseQuoting = true };

ChildStrategies.Add(new TakeProfitStopLossStrategy(takeProfit, stopLoss));

Один раз для TP стратегии, второй раз для SL - симптомы те же, исполняются 2 одинаковые по цене заявки с минимальной разницей во времени. Лог одного из случаев (SL):

SLS | 31.01.2012 13:13:11 || Защита активирована. SLS | 31.01.2012 13:13:11 || Регистрация защитного котирования. MQS | 31.01.2012 13:13:11 || Стратегия запущена. MQS | 31.01.2012 13:13:11 || Котирование на Sell объема 1. MQS | 31.01.2012 13:13:11 || Цена текущей NULL и лучшей 9080. MQS | 31.01.2012 13:13:11 || Лучший бид 9078 и лучший аск 9080. MQS | 31.01.2012 13:13:11 || Регистрация новой заявки на Sell с ценой 9080 и объемом 1. MQS | 31.01.2012 13:13:11 || Заявка 38516284 на Sell отправлена с ценой 9080 объемом 1. SLS | 31.01.2012 13:13:11 || Цена текущей NULL и лучшей 9080. SLS | 31.01.2012 13:13:11 || Лучший бид 9078 и лучший аск 9080. SLS | 31.01.2012 13:13:11 || Регистрация новой заявки на Sell с ценой 9080 и объемом 1. SLS | 31.01.2012 13:13:11 || Заявка 38516285 на Sell отправлена с ценой 9080 объемом 1. MQS | 31.01.2012 13:13:11 || Заявка 38516284 принята биржей. SLS | 31.01.2012 13:13:11 || Заявка 38516285 принята биржей. EmaCore | 31.01.2012 13:13:12 || Новая позиция 0. Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -39 :(, Slippage: 1, Position: 0, Latency: 00:00:00.5404569 Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -39 :(, Slippage: 1, Position: 0, Latency: 00:00:01.0506864 TPSLS | 31.01.2012 13:13:12 || Новая позиция -1. SLS | 31.01.2012 13:13:12 || Новая позиция -1. SLS | 31.01.2012 13:13:12 || Позиция изменилась на -1. Оставшийся объем 0. SLS | 31.01.2012 13:13:12 || Заканчиваем котирование. TPSLS | 31.01.2012 13:13:12 || Стратегия останавливается. Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -39 :(, Slippage: 1, Position: 0, Latency: 00:00:01.0506864 TPS | 31.01.2012 13:13:12 || Заканчиваем котирование с неисполненным объемом равный 1. TPS | 31.01.2012 13:13:12 || Стратегия останавливается. TPS | 31.01.2012 13:13:12 || Стратегия остановлена. SLS | 31.01.2012 13:13:12 || Отмена заявки 38516285. SLS | 31.01.2012 13:13:12 || Стратегия останавливается. MQS | 31.01.2012 13:13:12 || Заканчиваем котирование с неисполненным объемом равный 1. MQS | 31.01.2012 13:13:12 || Стратегия останавливается. MQS | 31.01.2012 13:13:12 || Стратегия остановлена. TPSLS | 31.01.2012 13:13:12 || Стратегия остановлена. EmaCore | 31.01.2012 13:13:12 || Новая позиция -1. Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -39 :(, Slippage: 1, Position: -1, Latency: 00:00:01.0506864 Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -39 :(, Slippage: 1, Position: -1, Latency: 00:00:01.5628213 EmaCore | 31.01.2012 13:13:12 || Новая Sell сделка 497392045 по цене 9080 на 1 заявки 38516284. Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -39 :(, Slippage: 1, Position: -1, Latency: 00:00:01.5628213 Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -37 :(, Slippage: 1, Position: -1, Latency: 00:00:01.5628213 Main App | 31.01.2012 13:13:12 || I've sold 1 futures contracts at 9080 EmaCore | 31.01.2012 13:13:12 || Новая Sell сделка 497392046 по цене 9080 на 1 заявки 38516285. Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -37 :(, Slippage: 1, Position: -1, Latency: 00:00:01.5628213 Main App | 31.01.2012 13:13:12 || Stat Changed. State: Started, PnL: -37 :(, Slippage: 1, Position: -1, Latency: 00:00:01.5628213 Main App | 31.01.2012 13:13:12 || I've sold 1 futures contracts at 9080

Кто может помочь советом, как починить?

Mikhail Sukhov
Mikhail Sukhov

MQS | 31.01.2012 13:13:11 || Заявка 38516284 принята биржей. SLS | 31.01.2012 13:13:11 || Заявка 38516285 принята биржей. EmaCore | 31.01.2012 13:13:12 || Новая позиция 0.

Кто может помочь советом, как починить?

А что чинить? Заявка зарегистрирована на бирже. Нужно сделать так, чтобы она не могла зарегистрироваться?

По проблеме автора этого топика отписал в той ссылке, которую он привел изначально. Не понятно, зачем было кросс посты вводить.

vfreeman
vfreeman Автор

ak: Столкнулся с такой же проблемой дважды причем подряд (QuikTrader, 4.0.17).

var takeProfit = new TakeProfitStrategy(trade, this.TakeProfitUnit) ; var stopLoss = new StopLossStrategy(trade, StopLossUnit) ;

ChildStrategies.Add(new TakeProfitStopLossStrategy(takeProfit, stopLoss));

> 
> Один раз для TP стратегии, второй раз для SL - симптомы те же, исполняются 2 одинаковые по цене заявки с минимальной разницей во времени. Лог одного из случаев (SL):
> 
> 
> Кто может помочь советом, как починить?

мне помогло Security.Exchange.IsSupportAtomicReRegister = false
Serg
Serg

А можно посмотреть код MarketQuotingStrategy? если это квик то тут скорее всего проблема с тем что приходит раньше(заявка/сделка).

ak
ak

OK. Михаил, поясните пожалуйста еще раз.

Есть стратегия:


var stopLoss = new StopLossStrategy(trade, StopLossUnit) { UseQuoting = true };

Я предполагаю, что выставив фалг UseQuoting, при касании ценой StopLossUnit, стратегия SLS создаст стратегию MQS, которая, выставляя лимитные ордера, и двигая их по необходимости, добьется исполнения защитного ордера. Затем завершится сама MQS (поражденная SLS стратегией), а затем и родительская SLS.

По факту исполняется 2а ордера с одинаковым объемом, причем:

1ый ордер создается MQS стратегией:

MQS | 31.01.2012 13:13:11 || Регистрация новой заявки на Sell с ценой 9080 и объемом 1. MQS | 31.01.2012 13:13:11 || Заявка 38516284 на Sell отправлена с ценой 9080 объемом 1.

2ой ордер создается SLS стратегией:

SLS | 31.01.2012 13:13:11 || Регистрация новой заявки на Sell с ценой 9080 и объемом 1. SLS | 31.01.2012 13:13:11 || Заявка 38516285 на Sell отправлена с ценой 9080 объемом 1.

Естественно, если выставить флаг UseQuoting в false, никакого дублирования не происходит. Так же как и обычные (не защитные) MQS стратегии отрабатывают нормально.

Откуда берется второй ордер?

ak
ak

Благодарю за совет, обязательно попробую! Но вероятно у меня все же другая ошибка, потому что обычные MQS, созданные мной, вроде этой:


MarketQuotingStrategy marketQuotingStrategy = new MarketQuotingStrategy(order, new Unit(), new Unit());
base.ChildStrategies.Add(marketQuotingStrategy);

работают нормально, происходит переставление ордера (без ошибок, которые появлялись у вас) и исполнение приказа без дублирования ордеров. А вот внутри защитных стратегий - дублируются.

Важное дополнение: при использовании RealTimeEmulationTrader<QuikTrader> вместо QuikTrader ошибка не реплицируется. На QuikTrader повторяется в 100% случаев у меня.

ak
ak

Проблема сохраняется, флаг Security.Exchange.IsSupportAtomicReRegister = false не помог.

ET
ET

_

Moadip
Moadip

MQS конкурирует со своими заявками. Хотя в этом посте написано что нет.

IsSupportAtomicReRegister = false IsAsyncMode = false

Это хорошо видно вечером или на неликвиде, когда стакан не двигается. Допустим мне надо скотировать один лот на продажу. Создается MQS, PriceOffset = Security.MinStepSize Например лучший бид 90, оффер 100, стакан не двигается. Так MQS будет постоянно снимать и переставлять заявку на 99,98,97. Т.е не держит ее на 99. Бывает что стратегия отрабатывает нормально, но в основном завершается с ошибкой

Плюс вопрос в конце данного поста тоже никак не решился.

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

Mikhail Sukhov
Mikhail Sukhov

Moadip: Думал что что нибудь изменится в последней сборке 4.0.20 но ничего не изменилось.

А в чем ошибка? Эта сообщение о невозможности переставить заявку. Она уже исполнена. Нормальная ситуация.

ET
ET

_

Moadip
Moadip

ET: Уважаемые разработчики есть ли возможность получить доступ к алгоритмам котирования? 😭

В этом посте. Но я думаю он уже устарел.

ET
ET

Moadip, спасибо, я даже этого не заметил.

Михаил, Александр! но все таки можно было бы получить код котирования по волатильности, маркет котирования? мне бы туда задержку ввести для ордера, чтоб можно было тестировать более реально приближенно к реальности. Если все таки это не возможно - не могли бы Вы вести данную логику в алгоритмы котирования, думаю для многих актуально это! все таки тест должен быть максимально приближен к способу соединения! Спасибо!

Alexander
Alexander

ET: Moadip, спасибо, я даже этого не заметил.

Михаил, Александр! но все таки можно было бы получить код котирования по волатильности, маркет котирования? мне бы туда задержку ввести для ордера, чтоб можно было тестировать более реально приближенно к реальности. Если все таки это не возможно - не могли бы Вы вести данную логику в алгоритмы котирования, думаю для многих актуально это! все таки тест должен быть максимально приближен к способу соединения! Спасибо!

Переопределите RegisterQuotingOrder

ET
ET

_

Alexander
Alexander

ET: спасибо! Александр, а код котирования по волатильности нельзя посмотреть? пожалуйста!😊

Можно. Надо понимать с какой целью только :) Может то что вы хотите сделать стоит делать без самого котирования, как в случае с задержкой для маркет котирования.

ET
ET

_

Alexander
Alexander

Готовы предоставить код котирования по волатильности в обмен на 1) пункт. Этот код (по 1 пункту) для внутреннего пользования, в S# включён не будет. Интересно посмотреть на код.

ET
ET

_

Alexander
Alexander

ET: вечером вам в скайп постучусь, напишите ваш скайп.

amukhanchikov и mika_soukhov. Лучше Михаилу, меня вечером может не быть.

Moadip
Moadip

Т.е когда стратегия завершается с ошибкой это нормальная ситуация?

Допустим выставил quotingVolume = 5, Volume = 1. Запускается MQS. После того как скотировано 2 лота, стратегия останавливается.

Т.е. в основной стратегии надо выставить

RemoveChildStrategies = false;

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

У MQS подписаться на событие Stopped и в нем смотреть LeftVolume, если больше нуля, то повторно запускать с quotingVolume = LeftVolume?

Mikhail Sukhov
Mikhail Sukhov

Moadip: Т.е когда стратегия завершается с ошибкой это нормальная ситуация?

Допустим выставил quotingVolume = 5, Volume = 1. Запускается MQS. После того как скотировано 2 лота, стратегия останавливается.

Если так ставить условия, то да, это ошибка. Но котирование не прекращает свою работу при возникновении ошибки при снятии или перерегистрации стратегии (см логи того же vfreeman, где у него таких ошибок было несколько). У вас что-то еще.

Moadip
Moadip

Вот еще один скрин, скотировалось 2 лота из 5, после чего MQS остановилась.

Код, проще некуда, для того чтобы проверить работу MQS. В чем проблема я понять не могу.

Выкладываю полностью весь код.

MainWindow.xaml.cs


using System.Linq;
using System.Windows;

using Ecng.Collections;
using Ecng.Xaml;
using StockSharp.BusinessEntities;
using StockSharp.Quik;

using StockSharp.Xaml;
using StockSharp.Algo.Logging;

using System.Windows.Forms;
using MessageBox = System.Windows.MessageBox;
using System.ComponentModel;


namespace Kotirovanie
{
    public partial class MainWindow : Window
    {
        public QuikTrader trader;

        static Security instr1;
        public static MarketDepth depth1;
        
        const string secCode1 = "SBER";

        myStrategy myStrat;

        readonly LogManager logManager;

        public MainWindow()
        {
            InitializeComponent();

            //Path.Text = QuikTerminal.GetDefaultPath();
            Path.Text = "c:\\Program Files\\QUIK-Junior\\";

            var monitor = new MonitorWindow() { Topmost = true };
            monitor.Show();

            logManager = new LogManager();
            logManager.Listeners.Add(new GuiLogListener(monitor));
        }

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

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

        bool isConnected;

        private void btnConnect_Click(object sender, RoutedEventArgs e)
        {
            if (!isConnected)
            {
                if (Path.Text.IsEmpty())
                    MessageBox.Show(this, "Путь к Quik не выбран");
                else
                {
                    if (trader == null)
                    {
                        trader = new QuikTrader(Path.Text) { IsAsyncMode = false };
                        logManager.Sources.Add(trader);

                        trader.ReConnectionSettings.Interval = TimeSpan.FromSeconds(10);
                        trader.ReConnectionSettings.WorkingTime = Exchange.Rts.WorkingTime;
                        trader.ReConnectionSettings.ConnectionRestored += () => this.GuiAsync(() => MessageBox.Show(this, "Соединение восстановлено"));
                        trader.ConnectionError += error => this.GuiAsync(() => MessageBox.Show(this, error.ToString()));
                        trader.Connected += () => this.GuiAsync(() => btnExportDde.IsEnabled = true);

                        trader.NewPortfolios += portfolios => this.GuiAsync(() => Portfolio.Portfolios.AddRange(portfolios));

                        trader.NewSecurities += securities =>
                        {
                            if (instr1 == null)
                            {
                                instr1 = securities.FirstOrDefault(sec => sec.Code == secCode1);
                                instr1.Exchange.IsSupportAtomicReRegister = false;
                            }
                        };

                        trader.QuotesChanged += depths =>
                        {
                            if (depth1 == null && instr1 != null)
                            {
                                depth1 = depths.FirstOrDefault(d => d.Security == instr1);
                            }
                        };
                    }

                    trader.Connect();

                    isConnected = true;
                    btnConnect.Content = "Отключиться";
                }
            }
            else
            {
                trader.Disconnect();

                isConnected = false;
                btnConnect.Content = "Подключиться";
            }
        }

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

        bool isDdeStarted;

        private void StartDde()
        {
            trader.StartExport();
            isDdeStarted = true;
        }

        private void StopDde()
        {
            trader.StopExport();
            isDdeStarted = false; 
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (trader != null)
            {
                if (isDdeStarted) StopDde();
                trader.Dispose();
            }
        }

        private void btnExportStakan_Click(object sender, RoutedEventArgs e)
        {
            trader.RegisterQuotes(instr1);
        }

        private void btnParent_Click(object sender, RoutedEventArgs e)
        {
            //Создаем и запускаем основную стратегию
            myStrat = new myStrategy() { Trader = trader, Portfolio = Portfolio.SelectedPortfolio, Security = instr1};
            logManager.Sources.Add(myStrat);
            myStrat.Start();
        }

        private void btnChild_Click(object sender, RoutedEventArgs e)
        {
            //Добавляем дочернюю
            myStrat.addChildStrategy(OrderDirections.Buy, 5, 1);
        }
    }
}

myStrategy.cs


using System;
using System.Collections.Generic;

using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;


namespace Kotirovanie
{
    class myStrategy : Strategy
    {
        protected override void OnStarting()
        {
            RemoveChildStrategies = false;
            base.OnStarting();
        }

        public void addChildStrategy(OrderDirections direct, decimal quotingVol, decimal vol)
        {
            var strt = new MarketQuotingStrategy(direct, quotingVol) { PriceOffset = Security.MinStepSize, Volume = vol };

            ChildStrategies.Add(strt);
        }
    }
}

MainWindow.xaml


<Window x:Class="Kotirovanie.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:EcngTradingXaml="clr-namespace:StockSharp.Xaml;assembly=StockSharp.Xaml"
        Title="" Height="173" Width="478" Closing="Window_Closing" Topmost="True" WindowStartupLocation="CenterScreen">
    <Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="Path" VerticalAlignment="Top" Width="277" />
        <Button Content="..." Height="23" HorizontalAlignment="Left" Margin="295,12,0,0" Name="FindPath" VerticalAlignment="Top" Width="23" Click="FindPath_Click" />
        <Button Content="Подключиться" Height="23" HorizontalAlignment="Left" Margin="12,41,0,0" Name="btnConnect" VerticalAlignment="Top" Width="98" Click="btnConnect_Click" />
        <Button Content="Экспорт DDE" Height="23" HorizontalAlignment="Left" Margin="116,41,0,0" Name="btnExportDde" VerticalAlignment="Top" Width="98" Click="btnExportDde_Click" IsEnabled="False" />
        <EcngTradingXaml:PortfolioComboBox x:Name="Portfolio" Height="23" HorizontalAlignment="Left" Margin="324,41,0,0" VerticalAlignment="Top" Width="120" />
        <Button Content="Экспорт Стаканы" Height="23" HorizontalAlignment="Left" Margin="220,41,0,0" Name="btnExportStakan" VerticalAlignment="Top" Width="98" Click="btnExportStakan_Click" />
        <Button Content="Основная" Height="23" HorizontalAlignment="Left" Margin="12,99,0,0" Name="btnParent" VerticalAlignment="Top" Width="98" Click="btnParent_Click" />
        <Button Content="Дочерняя" Height="23" HorizontalAlignment="Left" Margin="116,99,0,0" Name="btnChild" VerticalAlignment="Top" Width="98" Click="btnChild_Click" />
    </Grid>
</Window>

Михаил, посмотрите пожалуйста что я не так делаю?

Mikhail Sukhov
Mikhail Sukhov

Moadip: Михаил, посмотрите пожалуйста что я не так делаю?

Асинхронный режим включите.

Moadip
Moadip

Мда. Решение как всегда лежит на поверхности, но почему то его не видишь.

Я думал что чтобы наверняка заявки выставлялись/снимались лучше делать это в синхронном режиме. Оказалось нет.

Михаил, спасибо за ответ. А то я уже какой день мучаюсь с MQS.