Заметка

Стратегия "спот-фьючерс" на примере торговли индексом в Tradematic Trader

  2  

Мы продолжаем цикл статей, описывающих ньюансы использования Tradematic Trader — конструктора торговых роботов.
В этой статье мы рассмотрим достаточно часто возникающую задачу типа "спот-фьючерс", т.е. анализируем один инструмент — торгуем другим, на примере стратегии, анализирующей индекс ММВБ 10, а торгующей бумагами, в него входящими.

Достаточно часто возникает необходимость анализировать один инструмент, а торговать другим (или сразу несколькими).
Вот примеры стратегий, которые используют эту технику:

Торговля по индексу

Стратегия анализирует динамику индекса, а торгует бумагами, входящими в него.
График индекса всегда более сглаженный и менее волатильный, что позволяет повысить качество работы многих индикаторов и увеличить доходность по стратегии.
Кроме того, купить сам индекс не возможно чисто технически.

Спот-фьючерс

Анализируется базовый актив (например, акция Сбербанка), а торгуется фьючерс на Сбербанк.
Смысл этой стратегии — в значительной экономии на издержках (на рынке ФОРТС значительно ниже брокерские комиссии), а так же фактически использование бесплатных заемных средств (вместо полной стоимости контракта блокируется только гарантийное обеспечение).

Создание стратегии

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

В качестве основы мы снова возьмем нашу любимую стратегию SMA-9, чтобы было нагляднее.
В качестве индекса мы берем индекс ММВБ10, который на текущий момент включает следующие бумаги: ВТБ ао, ГАЗПРОМ ао, ГМКНорНик, ЛУКОЙЛ, Роснефть, РусГидро, Сбербанк, Сбербанк-п, СевСт-ао, Сургнфгз.

Важно! Все эти бумаги, а также индекс ММВБ 10, должны быть в списке инструментов в свойствах стратегии.

Технические аспекты

Трейдматик запускает скрипт по каждому из инструментов, указанных в свойствах стратегии. Это значит, что в коде мы должны будем проверять, по какому инструменту сейчас запущен скрипт, и:
- если это индекс ММВБ 10, то нужно выходить, т.к. по самому индексу мы ничего делать не будем
- если это не индекс ММВБ 10 (т.е. одна из входящих в него бумаг), то нам нужно получить индекс ММВБ10, проанализировать его, и если есть сигнал, открыть/закрыть позицию по текущему инструменту

Для получения внешнего инструмента (в данном случае индекса ММВБ10), т.е. инструмента, который сейчас не является текущим, используется функция Script.GetExternalSymbol(string symbol, bool synchronize).

Нам нужно получить внешний инструмент с именем "MICEX 10", и уже на основе него строить индикаторы и проверять условия:

// Получаем индекс ММВБ10
Symbol micex10 = GetExternalSymbol("MICEX 10", true);

Отрисовка на графиках и проверка

Нам нужно вывести индекс ММВБ 10 на всех графиках акций.

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

// Отрисовка
ChartPane micexPane = CreatePane(50, false);
PlotSymbol(micexPane, micex10, Color.Green, Color.Red);
PlotSeries(micexPane, SMA.Series(micex10.Close, parameter0.ValueInt), Color.Red, LineStyle.Solid, 1);
PlotSeries(micexPane, SMA.Series(micex10.Close, parameter1.ValueInt), Color.Red, LineStyle.Solid, 1);

Не забываем добавить проверку в функцию Execute(), чтобы по самому индексу сигналы не выдавались:

// Проверка
if(Symbol.SymbolName == "MICEX 10")
{
   return;
}

Кроме того, в список инструментов по стратегии, кроме списка индекса ММВБ10 (он приведен выше), нужно включить и сам индекс.

Итоговый код

Итоговый код стратегии получается таким:

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using TradeMatic;
using TradeMatic.Indicators;

namespace ScriptNamespace
{
   class MyScript : Script
   {
      private StrategyParameter parameter0;
      private StrategyParameter parameter1;

      public MyScript()
      {
         parameter0 = CreateParameter("Период SMA", 9, 0, 100, 1);
         parameter1 = CreateParameter("Период SMA", 9, 0, 100, 1);
      }

      public override void Execute()
      {
         // Проверка
         if(Symbol.SymbolName == "MICEX 10")
         {
            return;
         }
                  
         // Получаем индекс ММВБ10
         Symbol micex10 = GetExternalSymbol("MICEX 10", true);
         
         // Отрисовка
         ChartPane micexPane = CreatePane(50, false);
         PlotSymbol(micexPane, micex10, Color.Green, Color.Red);
         PlotSeries(micexPane, SMA.Series(micex10.Close, parameter0.ValueInt), Color.Red, LineStyle.Solid, 1);
         PlotSeries(micexPane, SMA.Series(micex10.Close, parameter1.ValueInt), Color.Red, LineStyle.Solid, 1);

         // Инициализация

         
         // Основной цикл
         for (int bar = 9; bar < micex10.Count; bar++)
         {
            if (IsLastPositionActive)
            {
               if (CrossUnder(bar, micex10.Close, SMA.Series(micex10.Close, parameter1.ValueInt)))
               {
                  SellAtClose(bar, LastPosition, "");
               }
            }
            else
            {
               if (CrossOver(bar, micex10.Close, SMA.Series(micex10.Close, parameter0.ValueInt)))
               {
                  BuyAtClose(bar, "");
               }
            }
         }
      }
   }
}

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

Спасибо, что потратили свое время на чтение этой статьи! :)

Комментарии

Pablo4646 — 8 ноября 2012 г.

"Анализируется базовый актив (например, акция Сбербанка), а торгуется фьючерс на Сбербанк. " Все это здорово. Но не подскажете , как просто синхронизировать два набора данных фьючерс на Сбер и сам Сбер? Тк Трейдматик выдает ошибку из-за этого
// Основной цикл
for (int bar = 9; bar < SBER.Count; bar++)

0 +

Flyanimal — 18 февраля 2013 г.

Pablo4646, Похоже в ТМ синхронизировать одну позицию отнеосительно другой пока невозможно.

0 +

k-126525 — 6 марта 2013 г.

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

0 +

orekton — 6 марта 2013 г.

k-126525, можно сделать и это: с помощью переменных задать точку входа и считать от нее результат по внешнему инструменту.

0 +

k-126525 — 6 марта 2013 г.

orekton, ну это не робот получится, а неизвестно что - у меня торгует фьюч ртс на 15-минутках, по 2-3 сделки в день. Караулить каждую сделку и считать от нее стоп-лоссы - это мне с работы придется уволиться и заниматься только этим...

0 +

orekton — 6 марта 2013 г.

k-126525, караулить ничего не надо. все автоматически. анализиурем один иснтрумент, а совершаем сделки по другому. смотрим на анализируемый инструмент a = цена входа. стоп, например, можем задать таким образом SBER.Close[bar]a*parameter17.Value

1 +

k-126525 — 6 марта 2013 г.

orekton, о, спасибо, попробую!

0 +

k-126525 — 6 марта 2013 г.

orekton, Если не затруднит, напишите как задавать а=цена входа, и куда это прописывать. Для чайников )

0 +

orekton — 7 марта 2013 г.

k-126525, ниже простой пример. входим в лонг после появления белой свечи на графике сбербанка. выходим, когда на графике сбербанка достигается уровень тейка или стопа. в качестве инструмента, по которому будем совершать сделки, можем использовать что угодно. чтобы протестировать нужно создать новый источник данных. файл с данными по сберу назвать SBER

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using TradeMatic;
using TradeMatic.Indicators;

namespace ScriptNamespace
{
class MyScript : Script
{

private StrategyParameter parameter1;
private StrategyParameter parameter2;


public MyScript()
{

parameter1 = CreateParameter("Тейк", 1.03, 1.01, 1.03, 0.01);
parameter2 = CreateParameter("Стоп", 0.99, 0.98, 0.99, 0.01);

}

public override void Execute()
{
if(Symbol.SymbolName == "SBER")
{
return;
}
Symbol SBER = GetExternalSymbol("SBER", true);

double price = 0;




// Основной цикл
for (int bar = 5; bar < SBER.Count; bar++)
{




if (MarketPosition == 1)
{




if (SBER.Close[bar]price*parameter2.Value)
{
SellAtClose(bar, LastPosition, "");

}



}

if (MarketPosition == 0)
{
// Вход в длинную позицию

if (SBER.Close[bar]>SBER.Open[bar])
{
BuyAtClose(bar, "");
price = SBER.Close[bar];
}

}



}
}
}
}

1 +

k-126525 — 7 марта 2013 г.

orekton,

BuyAtClose(bar, "");
price = SBER.Close[bar];

правильно ли я понимаю, что если мы торгуем контракт за 10200 рублей, то робот будет пытаться его купить по цнен сбера - 102 рубля? По-моему это бесполезно )

0 +

k-126525 — 7 марта 2013 г.

k-126525, Все понял, вопрос снимается

0 +

k-126525 — 12 марта 2013 г.

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

0 +

orekton — 12 марта 2013 г.

k-126525, чтобы протестировать мой пример источник данных по акции Сбербанка должен называться "SBER", источник данных по фьючу - как угодна. Оба источника должны находиться в одной папке. Если тестируете через брокер-адапетр, то Сбербанк в коде должен называться "Сбербанк":

if(Symbol.SymbolName == "Сбербанк")
{
return;
}
Symbol SBER = GetExternalSymbol("Сбербанк", true);

0 +

k-126525 — 13 марта 2013 г.

orekton, Это все понятно, я знаю как работать с источниками данных. Даже если все правильно указано - пример не работает в принципе. Он всегда закрывает сделку на той же свече, на которой открыл, без разницы что написано в условиях закрытия, и какое значение параметра.

0 +

orekton — 13 марта 2013 г.

k-126525, тейк - 3%, стоп - 1%

if (SBER.Close[bar]>price*parameter1.Value)
{
SellAtClose(bar, LastPosition, "");
}

else if (SBER.Close[bar]{
SellAtClose(bar, LastPosition, "");
}

0 +

Pablo4646 — 13 марта 2013 г.

orekton, Sber.Count и Symbol.Count - разные количества из-за вечерней сессии. bar будет не совпадать для спота и фьючерса. Нужен отдельный счетчик для каждого массива.

0 +

k-126525 — 13 марта 2013 г.

Pablo4646, Это решается, если в настройках tradematic в расписании указать время работы фортс до 18.45

0 +

Pablo4646 — 28 марта 2013 г.

k-126525, в таком случае те роботы, которые должны торговать на вечерке отключатся ? Это не решение. в вэлсе есть полезная вещь синхронизация. В Трейдматике я ее не нашел. Пробовал через Symbol.Delete(bar) поубирать лишнее. но тоже почему-то не работает. Мб техподдержка что-нибудь посоветует ?

0 +

orekton — 29 марта 2013 г.

Pablo4646, время работы скрипта можно ограничить в коде:
If (Date[bar].Hour < 19)
{
...
}

0 +

Pablo4646 — 29 марта 2013 г.

orekton, Время то можно ограничить. Но задача то не в этом! А в том чтобы bar external символа соответствовал bar торгуемого инструмента. иначе все наперекосяк. Пока решение вижу только в 2 счетчиках.

0 +

Николай Камынин — 7 марта 2013 г.

orekton,
Ваш пример демонстрирует заглядывание в будущее,
т е эта система успешно работает лишь на истории
Условие : Вход в длинную позицию
if (SBER.Close[bar]>SBER.Open[bar])
проверяется после возникновения сделки по цене SBER.Close[bar]
поэтому купить по этой цене Вы не можете, а Ваш алгоритм покупает:
BuyAtClose(bar, ""); price = SBER.Close[bar];
Это пример ,
как не надо писать алгоритмы,
если не хотите сливать депозит.

0 +

orekton — 7 марта 2013 г.

Николай, заглядывание в будущее имело бы место, если бы я покупал по Open[bar] после появления цены Close. В моем примере мы покупаем сразу после выполнения условия то есть фактически сделка происходит на Open[bar+1] Как показывают результаты тестирования, имеем мы в качестве цены входа значение Close[bar] или Open[bar+1] - на результат это не влияет.

0 +

Николай Камынин — 7 марта 2013 г.

orekton,
как я понял (если ошибся поправьте), но оператор
price = SBER.Close[bar];
означает, что купили по цене close свечи в момент выполнения условия
if (SBER.Close[bar]>SBER.Open[bar])
Но условие проверяется при уже совершенной сделке по Close свечи.
Close свечи - по определению это последняя сделка свечи
т е после нее сделок нет и Вы не можете совершить ни одной сделки на Close свечи.

0 +

Николай Камынин — 7 марта 2013 г.

дело в том что на истории все может быть нормально
Но такие системы называются "физически не реализуемые" т е как вечный двигатель.

0 +

Николай Камынин — 7 марта 2013 г.

т е хочу еще раз обратить Ваше внимание, что Close свечи - ПОСЛЕДНЯЯ СДЕЛКА в свече следующая сделка это Open следующей свечи. Поэтому если условие по Close то невозможно совершить и сделку по Close.

0 +

orekton — 7 марта 2013 г.

Николай, я вас понял. Такие системы физически реализуемы и я их успешно торгую уже достаточное колличество времени. В данном случае речь идет о таймреймах от 5 мин. до 1 часа. Видимо, говоря о нереализуемости, вы говорите о высокочастотных системах.

0 +

Flyanimal — 7 марта 2013 г.

В Трейдматике запись BuyAtClose(bar, ""); формально означает покупку по цене закрытия, которой еще нет, однако заглядывания в будущее тут отсутствует, просто такая форма записи, не очень корректная, на мой взгляд.

0 +

Николай Камынин — 7 марта 2013 г.

Flyanimal,
Дело в том,что закрытие свечи не может быть определено заранее, его можно определить как постфакт.
А фразу: "В Трейдматике запись BuyAtClose(bar, ""); формально означает покупку по цене закрытия, которой еще нет" Я вообще не могу понять. Вы не можете купить на закрытие свечи.
Вы лишь можете выставить заявку по цене закрытия но она исполнится или нет уже на следующей свече.
Трейдматик реализует алгоритм покупки по цене Close и если это на том же баре то это и есть заглядывание в будущее. Оно заключается в том, что Вы совершаете сделку которая уже совершилась до того как вы решили ее совершить - это Close Свечи.
~~~~~~~~~~~~~~~~~~~~~~~~~
orekton,
Вы заблуждаетесь , думая что торгуете такую систему, если бы это было так то все ваши заявки по цене закрытия всегда исполнялись в реале по этой цене , а так никогда не бывает.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Я лишь показал Вам некорректность такого подхода, а учитывать это или нет - это Ваш выбор.

0 +

Николай Камынин — 8 марта 2013 г.

tradematic,
Поясните плиз, что подразумевается и реализуется следующая Ваша конструкция:
~~~~~~~~~~~~~~~~~~~~~
f (SBER.Close[bar]>SBER.Open[bar])
{
BuyAtClose(bar, "");
price = SBER.Close[bar];
}
~~~~~~~~~~~~~~~~~~~
1) Вы на текущем баре в момент закрытия свечи совершаете покупку по цене закрытия?
2) Если "Да", то каким образом Вы это делаете, если цена закрытия - цена последней уже совершившейся сделки на текущем баре (bar).
3) Купить на этом баре уже ничего невозможно, так как очередная сделка - это уже новый бар.
~~~~~~~~~~~~~~~~~~
Спасибо.

0 +

tradematic — 3 мая 2013 г.

Николай Камынин,
естественно, нет. Конструкция BuyAtClose(bar) открывает длинную позицию по цене закрытия текущего бара на открытии следующего баре (аналогично конструкции BuyAtMarket(bar + 1))

0 +

Николай Камынин — 8 марта 2013 г.

и еще вопрос.. Как отрабатывается ситуация:
4) следующая сделка по цене много больше Close?
5) следующая сделка по цене много меньше Close?

0 +

k-126525 — 13 марта 2013 г.

Вобщем, опытным путем и с некоторой подсказкой от саппорта трейдматика, получилось следующее:

Cтоп-лосс:
вместо (LastPosition.NetProfitAsOfBarPercent(bar) < -parameter1.Value)
пишем (SBER.Close[bar-1] < SBER.Close[LastPosition.EntryBar]-((SBER.Close[LastPosition.EntryBar]/100) * parameter1.Value))

Если кто-нибудь подскажет как провернуть то же самое для (LastPosition.NetProfitAsOfBarPercent(bar)-LastPosition.MFEPercentAsOfBar(bar)) < -parameter1.Value
буду весьма признателен. Просто я уже весь мозг над этим сломал, в самом деле

0 +

Pablo4646 — 28 марта 2013 г.

k-126525, попробуй своими пременными рассчитывать профит, а не встроенными функциями. И все получится.

0 +

k-145534 — 13 марта 2013 г.

k-126525, а что это значит?:

0 +

k-126525 — 14 марта 2013 г.

k-145534, Это рассчет стоп-лосса, как если бы позиция была открыта по внешнему инструменту.

0 +

Написать комментарий

Чтобы написать комментарий, необходимо авторизоваться.

Написать администратору