← 戻る

Урок 3. Все о создании стратегий.

Видео-уроки:

Стратегии

[vk]http://vk.com/video_ext.php?oid=-66650972&id=167470523&hash=4b8b00e53a5b7a38&hd=3[/vk]

StrategyRule

[vk]http://vk.com/video_ext.php?oid=-66650972&id=167470520&hash=5a7de43868bcb7bc&hd=3[/vk]

Логирование

[vk]http://vk.com/video_ext.php?oid=-66650972&id=167470340&hash=d4a2baaf8c533bc8&hd=3[/vk]

Дочерние стратегии

[vk]http://vk.com/video_ext.php?oid=-66650972&id=167470334&hash=8beb60d403b41756&hd=3[/vk]

Темы занятия:

Работа со стратегиями

  1. Изучение класса Stratеgy
  2. Использование Strategy Rule( Once,Sync,Exclusive и т.д..)
  3. Два примера стратегий с использованием практически всех, рассказанных до этого StrategyRule StrategyRule
  4. Простые примеры StrategyRule
  5. Сделки Логирование
  6. Как работать с логированием
  7. Графическое отображение информации Дочерние стратегии
  8. Котирование
  9. Работа с тейк-профитом, стоплоссом и др. защитными стратегиями
  10. Создание своей собственной стратегии котирования Запускаем стратегию в S#.Studio (будущее)

Домашнее задание:

  1. Изучить визуальную панель для отображения сатистических параметров StatisticParameterPanel, добавить эту панель в окно пользователя и отобразить в ней информацию из стратегии.

Полезные ссылки: Класс Strategy Дочерние стратегии Логирование

Вложения: Скачать проекты

Изменения в проектах:

Проект StrategyRules Файл Signal.cs

В начало метода ProcessQuotes следует добавить проверку:


            if (NeededVolume <= 0)
                return;

это связано с тем, что метод: marketDepth.GetTheoreticalTrades(OrderDirections.Sell, NeededVolume) требует не нуливого объема, а в нашем случае получается следующее, мы создаем объект класса Signal, и в конструкторе подписываемся на получение новых котировок, и только потом указываем значение свойства NeededVolume, и до того как мы указали значение в NeededVolume может прийти котировка и метод: marketDepth.GetTheoreticalTrades(OrderDirections.Sell, NeededVolume) сгенерирует ошибку, т.к. значение свойства NeededVolume будет равно нулю.

Было:


        private void ProcessQuotes(IEnumerable<MarketDepth> marketDepths)
        {
            lock (_locker)
            {
                foreach (var marketDepth in marketDepths.Where(m => m.Security == Security))
                {
                    if (!marketDepth.Bids.Any() || !marketDepth.Asks.Any()) return;
                    //Суммарный объем
                    _bid.SumVolumes = marketDepth.TotalBidsVolume;
                    _ask.SumVolumes = marketDepth.TotalAsksVolume;
                    //сам сигнал
                    if (_bid.SumVolumes > _ask.SumVolumes)
                    {
                        _bid.Name = "Buy";
                        _ask.Name = "";
                    }
                    else
                    {
                        _bid.Name = "";
                        _ask.Name = "Sell";
                    }
                    //находим среднюю цену исполнения стакана
                    _bid.AverageMarketPrice = marketDepth.GetTheoreticalTrades(OrderDirections.Sell, NeededVolume).Average(t => t.Trade.Price);//.GetAveragePrice(OrderDirections.Sell, NeededVolume);
                    _ask.AverageMarketPrice = marketDepth.GetTheoreticalTrades(OrderDirections.Buy, NeededVolume).Average(t => t.Trade.Price);
                    //присваиваем лучшую цену
                    _bid.BestPrice = marketDepth.BestBid.Price;
                    _ask.BestPrice = marketDepth.BestAsk.Price;
                    //находим максимальный объем и цену у него 
                    var maxbidvolume = marketDepth.Bids.Max(s => s.Volume);
                    _bid.MaxVolume = maxbidvolume;
                    _bid.Price = marketDepth.Bids.FirstOrDefault(b => b.Volume == maxbidvolume).Price;

                    var maxaskvolume = marketDepth.Asks.Max(s => s.Volume);
                    _ask.MaxVolume = maxaskvolume;
                    _ask.Price = marketDepth.Asks.FirstOrDefault(b => b.Volume == maxaskvolume).Price;
                    //зажигаем событие
                    OnQuotesChanged();
                }
            }
        }

Стало:


        private void ProcessQuotes(IEnumerable<MarketDepth> marketDepths)
        {
            if (NeededVolume <= 0)
                return;

            lock (_locker)
            {
                foreach (var marketDepth in marketDepths.Where(m => m.Security == Security))
                {
                    if (!marketDepth.Bids.Any() || !marketDepth.Asks.Any()) return;
                    //Суммарный объем
                    _bid.SumVolumes = marketDepth.TotalBidsVolume;
                    _ask.SumVolumes = marketDepth.TotalAsksVolume;
                    //сам сигнал
                    if (_bid.SumVolumes > _ask.SumVolumes)
                    {
                        _bid.Name = "Buy";
                        _ask.Name = "";
                    }
                    else
                    {
                        _bid.Name = "";
                        _ask.Name = "Sell";
                    }
                    //находим среднюю цену исполнения стакана
                    _bid.AverageMarketPrice = marketDepth.GetTheoreticalTrades(OrderDirections.Sell, NeededVolume).Average(t => t.Trade.Price);//.GetAveragePrice(OrderDirections.Sell, NeededVolume);
                    _ask.AverageMarketPrice = marketDepth.GetTheoreticalTrades(OrderDirections.Buy, NeededVolume).Average(t => t.Trade.Price);
                    //присваиваем лучшую цену
                    _bid.BestPrice = marketDepth.BestBid.Price;
                    _ask.BestPrice = marketDepth.BestAsk.Price;
                    //находим максимальный объем и цену у него 
                    var maxbidvolume = marketDepth.Bids.Max(s => s.Volume);
                    _bid.MaxVolume = maxbidvolume;
                    _bid.Price = marketDepth.Bids.FirstOrDefault(b => b.Volume == maxbidvolume).Price;

                    var maxaskvolume = marketDepth.Asks.Max(s => s.Volume);
                    _ask.MaxVolume = maxaskvolume;
                    _ask.Price = marketDepth.Asks.FirstOrDefault(b => b.Volume == maxaskvolume).Price;
                    //зажигаем событие
                    OnQuotesChanged();
                }
            }
        }

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

トピックを共有

コメント (26)

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

pft_man
pft_man

Добрый день. В каком-то одном из уроков (к сожалению не помню, в каком) вы говорили о том, что последнюю сделку можно брать из стакана. Можно об этом подробней с парой строков кода? Я правильно понимаю, что если эту сделку брать из стакана, то она быстрее придёт, чем по событию всех сделок, поскольку все сделки отправляются пакетами и соответственно есть задержка на формирование этого пакета?

IvanB
IvanB 著者

pft_man: Добрый день. В каком-то одном из уроков (к сожалению не помню, в каком) вы говорили о том, что последнюю сделку можно брать из стакана. Можно об этом подробней с парой строков кода? Я правильно понимаю, что если эту сделку брать из стакана, то она быстрее придёт, чем по событию всех сделок, поскольку все сделки отправляются пакетами и соответственно есть задержка на формирование этого пакета? Стакан, это структура на основе заявок, по стакану нельзя получить информацию по сделкам. Из стакана можно получить лучшую цену продажи/покупки на данный момент.

albion8
albion8

Добрый день,

на Vimeo отсутствует видео "работа с котировками" https://vimeo.com/channels/mainstocksharp/59397647 Просьба добавить.

IvanB
IvanB 著者

albion8: Добрый день,

на Vimeo отсутствует видео "работа с котировками" https://vimeo.com/channels/mainstocksharp/59397647 Просьба добавить.

Видео добавлено

Николай
Николай

albion8: Подтверждаю, видео появилось. Спасибо!

IvanB:

albion8: Добрый день,

на Vimeo отсутствует видео "работа с котировками" https://vimeo.com/channels/mainstocksharp/59397647 Просьба добавить.

Видео добавлено

Так и не увидел, где добавленное видео.

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

Опять убрали???

albion8
albion8

Подтверждаю, видео появилось. Спасибо!

Николай
Николай

Добрый день.

Попробовал сделать третий урок первую часть - Стратегия.

После того как все сделал и запустил программу (на фьючерсах SIZ3), программа отказывалась выполнять сделки по купли и продаже.

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

 //========================= Для получения корректного значения рыночной цены с Quik ===============================
            var baseTrader = Trader as QuikTrader;
            if (baseTrader != null)
            {
                // Пробуем "научить" Квик-Трейдер правильно выставлять маркет-ордера при работе с фьючерсами 
                baseTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MaxPrice);
                baseTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MinPrice);
            }
            //=================================================================================================================

В результате стратегия стала покупать, однако отказывается выходить из сделки. Операция просто не выполняется:

15:33:30 TimeFrameCandle_SIZ3@FORTS_00-00-10 (O:33266, H:33266, L:33266, C:33266, V:9): {0}
15:33:40 TimeFrameCandle_SIZ3@FORTS_00-00-10 (O:33267, H:33267, L:33266, C:33266, V:10): {0}
signalStopBuy
15:33:50 TimeFrameCandle_SIZ3@FORTS_00-00-10 (O:33267, H:33267, L:33266, C:33266, V:70): {0}
signalStopBuy

И позиция с купленным фьючерсом продолжает висеть.

Подскажите пожалуйста:

В чем могут быть проблемы с ```csharp RegisterOrder(this.SellAtMarket());


И почему первоначальный вариант отказывался делать операции по фьючерсам в принципе?
IvanB
IvanB 著者

Николай: Добрый день.

Попробовал сделать третий урок первую часть - Стратегия.

После того как все сделал и запустил программу (на фьючерсах SIZ3), программа отказывалась выполнять сделки по купли и продаже.

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

Дело в том, что методы SellAtMarket и BuyAtMarket для фьючерсов используют цены, из столбцов МасимальнаяЦена и МинимальнаяЦена, для этого мы добавляем код:


 //========================= Для получения корректного значения рыночной цены с Quik ===============================
            var baseTrader = Trader as QuikTrader;
            if (baseTrader != null)
            {
                // Пробуем "научить" Квик-Трейдер правильно выставлять маркет-ордера при работе с фьючерсами 
                baseTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MaxPrice);
                baseTrader.SecuritiesTable.Columns.Add(DdeSecurityColumns.MinPrice);
            }
            //=================================================================================================================

И соответственно нужно добавить эти столбцы в Quik, что Вы не сделали, я предполагаю.

Еще есть вариант для получения маркет заявок - использовать расширенные методы SellAtMarketEx и BuyAtMarketEx, реализицию которых можно найти в проекте по пути (tfs): $/StockSharp Lessons/StockSharp.Edu/Additional/Algo/CommonStrategy

Николай
Николай

Иван,

Действительно замена BuyAtMarket на BuyAtLimit с ценой выставления превышающую BestAsk на несколько пунктов, изменило ситуацию. (аналогично с Sell)

Спасибо.

Николай
Николай

Возник еще один вопрос.

Правильно ли я понимаю что для фьючерсов не работает ClosePosition (закрытие открытых позиций)?

Есть ли аналог для фьючерсов или надо самому писать ? (Возможно просто перегрузить данный метод?)

IvanB
IvanB 著者

Николай: Возник еще один вопрос.

Правильно ли я понимаю что для фьючерсов не работает ClosePosition (закрытие открытых позиций)? Причина таже - метод использует маркет заявки, а для них надо добавлять в ручную столбцы в Quik и соответственно регистрировать в трейдере. Николай: Есть ли аналог для фьючерсов или надо самому писать ? (Возможно просто перегрузить данный метод?)

Можно перегрузить метод, за основу взять реализацию метода, но переписать на SellAtMarketEx и BuyAtMarketEx.


		/// <summary>
		/// Закрыть открытую позицию по рынку (выставить заявку типа <see cref="OrderTypes.Market"/>).
		/// </summary>
		/// <remarks>
		/// Рыночная заявка не работает на всех биржах.
		/// </remarks>
		/// <param name="strategy">Стратегия.</param>
		/// <param name="slippage">Уровень проскальзывания, допустимый при регистрации заявки. Используется, если заявка регистрируется лимиткой.</param>
		public static void ClosePosition(this Strategy strategy, decimal slippage = 0)
		{
			if (strategy == null)
				throw new ArgumentNullException("strategy");

			var position = strategy.Position;

			if (position != 0)
			{
				var volume = position.Abs();

				var order = position > 0 ? strategy.SellAtMarket(volume) : strategy.BuyAtMarket(volume);

				if (order.Type != OrderTypes.Market)
				{
					order.Price += (order.Direction == OrderDirections.Buy ? slippage : -slippage);
				}

				strategy.RegisterOrder(order);
			}
		}

https://stocksharp.codeplex.com/SourceControl/latest#Sources/Algo/Strategies/StrategyHelper.cs

JaguarFX
JaguarFX

При выполнении урока в момент вызова candlemanager.Start(candleseries)

    private void RunGetCandle(TimeSpan tf)
    {
        cm = new CandleManager(usUI.SafeCon.Trader);
        var iSec = usUI.SelectedSec;
        if (iSec == null)
        {
            MessageBox.Show("First select secutiry!");
            return;
        }
        cs = new CandleSeries(typeof (TimeFrameCandle), iSec, tf);

        cs.ProcessCandle += (cd) =>
            {
                if (cd.State != CandleStates.Finished)
                {return;
                }
                //Debug.WriteLine("Candle processed {0}", cd.ToString());
            };
        logManager.Sources.Add(cm);
        cm.Start(cs);

    }

ошибка {"Заданный аргумент находится вне диапазона допустимых значений.\r\nИмя параметра: min"} С чем это может быть связано? и что это вообще за параметр min? (в свойствах объектов CandleManager/CandleSeries/Security такой отсутствует)

JaguarFX
JaguarFX

В общем путем экспериментов установил что для TransaqTrader указанная выше ошибка не возникает, только для AlfaTrader.

IvanB
IvanB 著者

lebedevsrg: В общем путем экспериментов установил что для TransaqTrader указанная выше ошибка не возникает, только для AlfaTrader.

Надо стек ошибки посмотреть. В каком-то диапазоне не верно указана левая граница, только это сейчас можно выявить из имеющейся информации.

JaguarFX
JaguarFX

Вот стек

System.ArgumentOutOfRangeException не обработано HResult=-2146233086 Message=Заданный аргумент находится вне диапазона допустимых значений. Имя параметра: min Source=Ecng.ComponentModel ParamName=min StackTrace: в Ecng.ComponentModel.Range1.ValidateBounds(T min, T max) в Ecng.ComponentModel.Range1.Init(T min, T max) в Ecng.ComponentModel.Range`1..ctor(T min, T max) в StockSharp.Algo.Candles.CandleHelper.GetCandleBounds(TimeSpan timeFrame, DateTime currentTime, WorkingTime time) в StockSharp.Algo.Candles.CandleHelper.GetCandleBounds(TimeSpan timeFrame, DateTime currentTime, ExchangeBoard board) в StockSharp.Algo.Candles.CandleHelper.GetCandleBounds(TimeSpan timeFrame, Security security) в StockSharp.AlfaDirect.AlfaTrader.SubscribeCandles(CandleSeries series, DateTime from, DateTime to) в StockSharp.Algo.Candles.CandleManager.#=qMItUWtqqyxYV9eWUtO90aDhlD9POR4EPsQbWwGhMYSU=.#=qYfTpvUh_jC5dOKfp3oA$a$Vdsd0SvzCDXNDBrNjhXNm8y0N_S725XkJOiNmGVmlQbqWusBy_YGgt7iMjlsMuohgqhuSSw7olYEW7_ojgPDg=(CandleSeries #=qeXfORGiqD4X1Cbp9Je9U1A==, DateTime #=q1JcQ7uzX3vPwwrOdqkEouA==, DateTime #=qkxh3a7A69CubZ51Z$8WGAg==) в #=qdWC8DOndbS63yr7$WS97GpgXM4jJ2_pcgdHNKeXsN7j8Redf1iAVtJlNjy_cA0rszuybRYnmv1lBG8EMklOzzg==.#=qF_5wYMlMSSFtMdHs0xKGdA==() в StockSharp.Algo.Candles.CandleManager.Start(CandleSeries series, DateTime from, DateTime to) в StockSharp.Algo.Candles.CandleHelper.Start(ICandleManager manager, CandleSeries series) в SimpleStrategy.MainWindow.RunGetCandle(TimeSpan tf) в c:\Users\lsa\Documents\Visual Studio 2012\Projects\S# for traders\Lesson 3\SimpleStrategy\SimpleStrategy\MainWindow.xaml.cs:строка 86 в SimpleStrategy.MainWindow.ButtonBase_OnClick(Object sender, RoutedEventArgs e) в c:\Users\lsa\Documents\Visual Studio 2012\Projects\S# for traders\Lesson 3\SimpleStrategy\SimpleStrategy\MainWindow.xaml.cs:строка 114

Версия API 4.2.1.7

IvanB
IvanB 著者

lebedevsrg: Вот стек

System.ArgumentOutOfRangeException не обработано HResult=-2146233086 Message=Заданный аргумент находится вне диапазона допустимых значений. Имя параметра: min Source=Ecng.ComponentModel ParamName=min StackTrace: в Ecng.ComponentModel.Range1.ValidateBounds(T min, T max) в Ecng.ComponentModel.Range1.Init(T min, T max) в Ecng.ComponentModel.Range`1..ctor(T min, T max) в StockSharp.Algo.Candles.CandleHelper.GetCandleBounds(TimeSpan timeFrame, DateTime currentTime, WorkingTime time) в StockSharp.Algo.Candles.CandleHelper.GetCandleBounds(TimeSpan timeFrame, DateTime currentTime, ExchangeBoard board) в StockSharp.Algo.Candles.CandleHelper.GetCandleBounds(TimeSpan timeFrame, Security security) в StockSharp.AlfaDirect.AlfaTrader.SubscribeCandles(CandleSeries series, DateTime from, DateTime to) в StockSharp.Algo.Candles.CandleManager.#=qMItUWtqqyxYV9eWUtO90aDhlD9POR4EPsQbWwGhMYSU=.#=qYfTpvUh_jC5dOKfp3oA$a$Vdsd0SvzCDXNDBrNjhXNm8y0N_S725XkJOiNmGVmlQbqWusBy_YGgt7iMjlsMuohgqhuSSw7olYEW7_ojgPDg=(CandleSeries #=qeXfORGiqD4X1Cbp9Je9U1A==, DateTime #=q1JcQ7uzX3vPwwrOdqkEouA==, DateTime #=qkxh3a7A69CubZ51Z$8WGAg==) в #=qdWC8DOndbS63yr7$WS97GpgXM4jJ2_pcgdHNKeXsN7j8Redf1iAVtJlNjy_cA0rszuybRYnmv1lBG8EMklOzzg==.#=qF_5wYMlMSSFtMdHs0xKGdA==() в StockSharp.Algo.Candles.CandleManager.Start(CandleSeries series, DateTime from, DateTime to) в StockSharp.Algo.Candles.CandleHelper.Start(ICandleManager manager, CandleSeries series) в SimpleStrategy.MainWindow.RunGetCandle(TimeSpan tf) в c:\Users\lsa\Documents\Visual Studio 2012\Projects\S# for traders\Lesson 3\SimpleStrategy\SimpleStrategy\MainWindow.xaml.cs:строка 86 в SimpleStrategy.MainWindow.ButtonBase_OnClick(Object sender, RoutedEventArgs e) в c:\Users\lsa\Documents\Visual Studio 2012\Projects\S# for traders\Lesson 3\SimpleStrategy\SimpleStrategy\MainWindow.xaml.cs:строка 114

Версия API 4.2.1.7 Ошибка возникает в оригинальном коде урока? Есть подозрение, что инфраструктура настроена не верно, что влечет к ошибке.

Aton5
Aton5

Здравствуйте! На Vimeo отсутствует видео "Видео-уроки (экстра): Отслеживание сигналов по котировкам (00:09:50)" т.е. "работа с котировками" https://vimeo.com/channels/mainstocksharp/59397647 Просьба добавить.

archmag
archmag

Здравствуйте! Не увидел, где можно скачать проекты-коды из уроков.

IvanB
IvanB 著者

archmag: Здравствуйте! Не увидел, где можно скачать проекты-коды из уроков.

http://stocksharp.com/forum/3885/TFS--proiekty--chaty--komandnaia-rabota/

devruss
devruss

С уроком 3 Логгирование есть проблемы:

Все уроки построены на версии S# 4.1.1.19, в то время как текущая ветка S# 4.2.x. В примерах используется StockSharp.TraderConnection.dll и StockSharp.WPFConnectionInterface.dll, которые основаны на ветке 4.1.x (и соответсвенно на BaseTrader вместо Connector). Даже если собрать .TraderConnection.dll и .WPFConnectionInterface.dll по урокам 1 и 2 самому, и заменить References, то возникают проблемы с запуском урока:

  • В уроках не рассматривался метод ConnectionInterFace.PushInformationToStrategy(), соответвсенно в собственных библиотеках его нет, что и как он делает непонятно - проект уже не запускается
  • Если делать все самому, заменить рефы на свои и попытаться собрать проект, то при компиляции вылетает ошибка на MonitorWindow _monitorWindow = new MonitorWindow() - XamlParseException occurred: "The invocation of the constructor on type 'StockSharp.Xaml.LogSourceTree' that matches the specified binding constraints threw an exception."

<mark>Огромная просьба как можно быстрее пересобрать .TraderConnection.dll и .WPFConnectionInterface.dll для ветки 4.2.x так как на них базируются все уроки, начиная с 3 </mark>

Возможно будут еще ошибки, но пока скомпилировать и запустить проект невозможно из-за текущих проблем. Очень жаль, так как урок классный, хотелось бы поиграть с разными настройками и посмотреть что можно сделать вне рамок данного урока

devruss
devruss

Также StockSharp.Xaml из ветки 4.2.x не подходит к примерам в уроках, нужно использовать только версию от 4.1.1.x

Валентин Мирошниченко

Мы уже переносим примеры на новую версию библиотеки. Совсем скоро они будут доступны на нашем сервере.

andy_baka
andy_baka

Господа, добрый день!

Из урока про дочерние стратегии пытаюсь просто повторить пример:

        _order.WhenNewTrades().Do(trades => trades.ForEach(t =>
            {
                var stoploss = new StopLossStrategy(t, 5);
                ChildStrategies.Add(stoploss);

            })).Apply(this);

Ругается на конструкцию trades => trades.ForEach

Что не так сделано?

Ecng.Collections включен.

Библиотека - 4.2.18

Mikhail Sukhov
Mikhail Sukhov

Предлагаю общение в скайп перенести http://stocksharp.com/forum/4390/Tiekhpoddierzhka-v-Skype--Khoroshiie-novosti/ Сейчас только там все общаются. Кстати, вопрос задавали уже несколько раз этот.

andy_baka
andy_baka

Спасибо, Михаил

Николай
Николай

Подскажите кто-нибудь пытался запускать пример со стратегией stoploss и takeprofit ? Это из урока 3 часть 4 (TestingStrategy).

У меня почему-то эти стратегии не работают. Пишет в логе, что позиция защищена, но не срабатывает вообще ни stoploss ни takeprofit.

Работаю через Quick 7.2.1.5

Есть у кого-то похожие проблемы?