Список форумов AmiSite.ru AmiSite.ru
Форум по Ами
 FAQ  •  Поиск  •  Пользователи  •  Группы   •  Регистрация  •  Профиль  •  Войти и проверить личные сообщения  •  Вход
 И снова scale-out Следующая тема
Предыдущая тема
Начать новую тему  Ответить на тему
Автор Сообщение
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Ср Дек 09, 2020 9:38 pm Ответить с цитатой Вернуться к началу

По моему нет. Только Sell.

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
rupiter



Зарегистрирован: 16.09.2013
Сообщения: 75

СообщениеДобавлено: Вт Дек 29, 2020 1:15 pm Ответить с цитатой Вернуться к началу

В общем, все это время пытался решить эту проблему. Так и не решил. Естественно, пришлось залезть в кастомный тестер.

Код:

 for( sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
        {
            bo.RawTextOutput( "\t" + "Positionsize: " + ( sig.PosSize * -1 - 2000 ) );

            if( sig.IsEntry() )
                bo.EnterTrade( i, sig.Symbol, sig.IsLong(), sig.Price, sig.PosSize );

            if( sig.IsExit() )
                bo.ExitTrade( i, sig.Symbol, sig.Price );

            if( sig.IsScale() AND sig.Type == 5 )
                bo.ScaleTrade( i, sig.Symbol, True, sig.Price, sig.PosSize );

            if( sig.IsScale() AND sig.Type == 6 )
            {
                trade = bo.FindOpenPos( sig.Symbol );
               
                bo.RawTextOutput( "\t" + "trade.shares: " + trade.Shares );
                bo.RawTextOutput( "\t" + "sig.PosSize: " + (sig.PosSize * -1 - 2000) );
                               
                if( trade AND (trade.Shares <= ( sig.PosSize * -1 - 2000 )) )
                {
                    bo.RawTextOutput( "\t" + "This is exit in scaleout");
                    bo.ExitTrade( i, sig.Symbol, sig.Price );
                }
                else
                {
                    bo.RawTextOutput( "\t" + "This is scaleout");
                    bo.ScaleTrade( i, sig.Symbol, False, sig.Price, sig.PosSize );
                }
            }
        }


Когда sig.Type == 6, это означает ScaleOut. Дальше идет проверка: если количество акций в открытой позиции меньше или равно количеству акций по сигналу продажи, то осуществляется закрытие позиции. Иначе - просто уменьшение. Так вот, в детальном отчете видно, что ScaleOut в самом деле меняется на Exit, но, видимо, какой-то недокументированный флаг открытой позиции все равно отмечает позицию открытой.
Если я тестирую позиции только в лонг или только в шорт, все идет нормально. Но если, допустим, у меня открытвается позиция в лонг, потом пару закрывается (частично и полностью), а потом открывается позиция в шорт, начинается какой-то треш с появлением сигнала за закрытие лонга. (Это в случае, если в тестере стоит включенным флаг Reverse entry signal forces exit). Если же этого флага нет, то сигнал в шорт вообще игнорируется, как будто позиция в лонг все еще открыта.

Ну вот разве я многого хочу? Мне нужно, чтобы торговая система следила за размером открытой позиции. И как только все акции проданы, позиция должна быть закрыта. В Tradestation это в одну строчку делается. Здесь же мало того, что сама концепция управление позицией очень сложная, так еще и не работает... А на форуме Амиброкера нашел ответ Томаша на вопрос о Low level Custom Backtesting - вы, говорит, вообще это не трогайте. Не для вас оно сделано! Ну, офигеть теперь!.
Посмотреть профиль Отправить личное сообщение
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Вт Дек 29, 2020 4:47 pm Ответить с цитатой Вернуться к началу

А если взять цикл как на первой странице обсуждения и добавить туда проверку на размер позиции == 0 и если равно 0, то закрывать?

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
rupiter



Зарегистрирован: 16.09.2013
Сообщения: 75

СообщениеДобавлено: Ср Дек 30, 2020 10:34 am Ответить с цитатой Вернуться к началу

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

Код:
if (trade.Shares <= ( sig.PosSize * -1 - 2000 ))


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

Если интересно, вот, собственно, сам код:

Код:

//Кастомный тестер
SetCustomBacktestProc( "" );

if( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();   //  Get backtester object

    bo.PreProcess();   //  Do pre-processing
   
   
    doDetailedLog = GetOption( "PortfolioReportMode" ) == 1;
    dt = DateTime();

    for( i = 0; i < BarCount; i++ )   //  Loop through all bars
    {
        //Следующий блок посвящен исключительно формированию детального лога и не влияет на результат
        if( doDetailedLog )
        {
            bo.RawTextOutput( NumToStr( dt[i], formatDateTime ) );

            cntEntrySig = bo.GetSignalQty( i, 1 );
            cntExitSig = bo.GetSignalQty( i, 2 );
            bo.RawTextOutput( "\t" + "# Entry Signals=" + cntEntrySig + ".  # Exit Signals=" + cntExitSig + "." );

            entrySigList = "\tEntry Signals(score): ";
            exitSigList = "\tExit Signals: ";

            for( sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
            {
                if( sig.IsEntry() )
                {
                    if( sig.IsLong )
                        dir = "Buy";
                    else
                        dir = "Short";

                    entrySigList += sig.Symbol + "=" + dir + "(" + sig.PosScore + "), ";
                }

                if( sig.IsExit() )
                {
                    bo.RawTextOutput( "\t Exit Sig: " + sig.Symbol + " Price=" + sig.Price + " isExit=" + sig.isExit + " isLong=" + sig.IsLong + " reason=" + sig.Reason + " type=" + sig.type );

                    if( sig.IsLong )
                        dir = "Sell";
                    else
                        dir = "Cover";

                    exitSigList += sig.Symbol + "=" + dir + ", ";
                }
            }

            bo.RawTextOutput( entrySigList );
            bo.RawTextOutput( exitSigList );
        }
      
      //Здесь начинается кастомный бэктестинг
      //На каждом баре проводится проверка наличия сигналов и их обработка
      
        for( sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
        {
            bo.RawTextOutput( "\t" + "Positionsize: " + ( sig.PosSize * -1 - 2000 ) ); // это просто комментарий, который отобразится в детальном логе

            if( sig.IsEntry() )
                bo.EnterTrade( i, sig.Symbol, sig.IsLong(), sig.Price, sig.PosSize );

            if( sig.IsExit() )
                bo.ExitTrade( i, sig.Symbol, sig.Price );

            if( sig.IsScale() AND sig.Type == 5 )
                bo.ScaleTrade( i, sig.Symbol, True, sig.Price, sig.PosSize );
         
         //В следующем блоке содержится непонятная проблема
         //Здесь обрабатываются сигналы на ScaleOut
            if( sig.IsScale() AND sig.Type == 6 )
            {
                trade = bo.FindOpenPos( sig.Symbol );
               
                bo.RawTextOutput( "\t" + "trade.shares: " + trade.Shares );
                bo.RawTextOutput( "\t" + "sig.PosSize: " + (sig.PosSize * -1 - 2000) );

            // Здесь я проверяю наличие открытой позиции, и сравниваю размер позиции с размером сигнала на Scaleout.
            // Если все условия утвердительны, ScaleOut заменяется на действие Exit
                if( trade AND (trade.Shares <= ( sig.PosSize * -1 - 2000 )) )
                {
                    bo.RawTextOutput( "\t" + "This is exit in scaleout");
                    bo.ExitTrade( i, sig.Symbol, sig.Price );
                }
                else // иначе, оставляю ScaleOut
                {
                    bo.RawTextOutput( "\t" + "This is scaleout");
                    bo.ScaleTrade( i, sig.Symbol, False, sig.Price, sig.PosSize );
                }
            }
        }
      // Стандартная обработка служебных вещей
        bo.HandleStops( i );   //  Handle programmed stops at this bar
        bo.UpdateStats( i, 1 );   //  Update MAE/MFE stats for bar
        bo.UpdateStats( i, 2 );   //  Update stats at bar's end
    }   //  End of for loop over bars

    bo.PostProcess();   //  Do post-processing
}

//Код основной программы. Сперва выполняется он.
//Вход в лонг выполняется 7 октября, выход 28 октября и 7 ноября 2019
//Вход в шорт 20 февраля 2020, выход 10 марта 2020
//Входы и выходы - скейлами

Sell = 0;

Cover = 0;

Buy = IIf( DateNum() == 1191007, sigScaleIn, IIf( ( DateNum() == 1191028 OR DateNum() == 1191107 ), sigScaleOut, 0 ) );

Short = IIf( DateNum() == 1200220, sigScaleIn, IIf( DateNum() == 1200310, sigScaleOut, 0 ) );


//Изменяем размер выхода, в зависимости от даты
SetPositionSize( IIf( DateNum() == 1191028, 50, 100 ), spsShares );
Посмотреть профиль Отправить личное сообщение
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Ср Дек 30, 2020 1:55 pm Ответить с цитатой Вернуться к началу

Вообще любопытно. По идее bo.ExitTrade должен бы закрывать позицию полностью. Странно.
Гляну...

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
rupiter



Зарегистрирован: 16.09.2013
Сообщения: 75

СообщениеДобавлено: Ср Дек 30, 2020 5:08 pm Ответить с цитатой Вернуться к началу

Спасибо.

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

P.S. Еще один момент. В детальном логе в моменты ScaleOut и Exit отмечается, что присутствуют 2 сигнала (во время входа - один). Что это за второй сигнал, я так и не понял. Строчка #22 в коде
Код:
cntExitSig = bo.GetSignalQty( i, 2 );

находит 2 сигнала на выход каждый раз, когда происходит уменьшение позиции.
Посмотреть профиль Отправить личное сообщение
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Чт Дек 31, 2020 6:52 pm Ответить с цитатой Вернуться к началу

По моему забыл
Код:
bo.ProcessTradeSignals( i );

Код:

//Кастомный тестер
SetCustomBacktestProc( "" );

if( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();   //  Get backtester object
    bo.PreProcess();   //  Do pre-processing

    for( i = 0; i < BarCount; i++ )   //  Loop through all bars
    {

      //Здесь начинается кастомный бэктестинг
      //На каждом баре проводится проверка наличия сигналов и их обработка
     
        for( sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
        {

            if( sig.IsEntry() )
                bo.EnterTrade( i, sig.Symbol, sig.IsLong(), sig.Price, sig.PosSize );

            if( sig.IsExit() )
                bo.ExitTrade( i, sig.Symbol, sig.Price );

            if( sig.IsScale() AND sig.Type == 5 )
                bo.ScaleTrade( i, sig.Symbol, True, sig.Price, sig.PosSize );
         
         //В следующем блоке содержится непонятная проблема
         //Здесь обрабатываются сигналы на ScaleOut
            if( sig.IsScale() AND sig.Type == 6 )
            {
                trade = bo.FindOpenPos( sig.Symbol );
               
            // Здесь я проверяю наличие открытой позиции, и сравниваю размер позиции с размером сигнала на Scaleout.
            // Если все условия утвердительны, ScaleOut заменяется на действие Exit
                if( trade AND (trade.Shares <= ( sig.PosSize * -1 - 2000 )) )
                {
                    bo.ExitTrade( i, sig.Symbol, sig.Price );
                }
                else // иначе, оставляю ScaleOut
                {
                    bo.ScaleTrade( i, sig.Symbol, False, sig.Price, sig.PosSize );
                }
                bo.ProcessTradeSignals( i );
            }
        }
      // Стандартная обработка служебных вещей
        bo.HandleStops( i );   //  Handle programmed stops at this bar
        bo.UpdateStats( i, 1 );   //  Update MAE/MFE stats for bar
        bo.UpdateStats( i, 2 );   //  Update stats at bar's end
       

    }   //  End of for loop over bars

    bo.PostProcess();   //  Do post-processing
}

//Код основной программы. Сперва выполняется он.
//Вход в лонг выполняется 7 октября, выход 28 октября и 7 ноября 2019
//Вход в шорт 20 февраля 2020, выход 10 марта 2020
//Входы и выходы - скейлами


Sell = Cover = 0;
Buy =    IIf( DateNum() == 1201201, 1, IIf( ( DateNum() == 1201203 OR DateNum() == 1201207 ), sigScaleOut, 0 ) );
Short = IIf( DateNum() == 1201209, 1, IIf( DateNum() == 1201211, sigScaleOut, 0 ) );

//Изменяем размер выхода, в зависимости от даты
SetPositionSize( IIf( DateNum() == 1201201 OR DateNum() == 1201209, 100, 50 ), spsShares );

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Чт Дек 31, 2020 11:09 pm Ответить с цитатой Вернуться к началу

Не. Нифига. Не оно.. Не работает. Сукаааа.

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Пт Янв 01, 2021 12:52 pm Ответить с цитатой Вернуться к началу

В общем так.
Тестирование при помощи porfolio backtester interface проходит 2 фазы
1 фаза - обработка сигналов
2 фаза - симуляция торговли.
То, что мы описываем после SetOption("UseCustomBacktestProc", True ) это вторая фаза. Из второй фазы повлиять на первую невозможно.
Поэтому если после сигнала Buy никакие другие сигналы на открытие позиции просто не попадают во вторую фазу пока не будет сигнала Sell. Невозможно закрыть позицию используя sigScaleOut. Т.е. физически она станет равной 0 и даже будет считаться закрытой, но последующий сигналы тупо не будут приходить т.к. они фильтруются в первой фазе.
И если противоположный сигнал все таки открыть можно используя Reverse entry signal forces exit, то сигнал в ту же сторону вообще никак не откроешь.
А в остальном код, после моей поправки, нормально работает.

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
rupiter



Зарегистрирован: 16.09.2013
Сообщения: 75

СообщениеДобавлено: Сб Янв 02, 2021 10:48 am Ответить с цитатой Вернуться к началу

Олег,
вот это:
Код:
bo.ProcessTradeSignals( i );

вставлять никак нельзя. Кастомный бэктестер работает в трех режимах: hi-level, mid-level, low-level. Эта операция относится к среднему уровню. Мы же занимаемся ручной обработкой сигналов, поэтому выбираем low-level. Если вставить эту функцию, она будет конфликтовать с тем, что мы делали до этого (манипулировали сигналами).

В Амиброкере есть сниппеты кодов:

Mid-level:
Код:
SetCustomBacktestProc("");

if (Status("action") == actionPortfolio)
{
    bo = GetBacktesterObject();   //  Get backtester object
    bo.PreProcess();   //  Do pre-processing (always required)

    for (i = 0; i < BarCount; i++)   //  Loop through all bars
    {
        for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
        {   
              // do your custom signal processing
        }   
       
       bo.ProcessTradeSignals( i );   //  Process trades at bar (always required)
    }    
     
    bo.PostProcess();   //  Do post-processing (always required)
}


Low-level:
Код:
SetCustomBacktestProc("");

if (Status("action") == actionPortfolio)
{
    bo = GetBacktesterObject();   //  Get backtester object
   
    bo.PreProcess();   //  Do pre-processing
   
    for (i = 0; i < BarCount; i++)   //  Loop through all bars
    {
        for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
        {   //  Loop through all signals at this bar
       
           if( sig.IsEntry() )
                bo.EnterTrade( i, sig.Symbol, sig.IsLong(), sig.Price, sig.PosSize );
               
           if( sig.IsExit() )
                bo.ExitTrade( i, sig.Symbol, sig.Price );
         
        }   
       
        bo.HandleStops( i );   //  Handle programmed stops at this bar
        bo.UpdateStats( i, 1 );   //  Update MAE/MFE stats for bar
        bo.UpdateStats( i, 2 );   //  Update stats at bar's end
    }   //  End of for loop over bars
   
    bo.PostProcess();   //  Do post-processing
}

В Low-level видно, что bo.ProcessTradeSignals( i ); отсутствует.

Все равно, спасибо. Буду копать дальше.
Посмотреть профиль Отправить личное сообщение
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Сб Янв 02, 2021 11:05 am Ответить с цитатой Вернуться к началу

Попробуй мой код и увидишь, что с он работает корректно и не открывает 2 позиции.

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Сб Янв 02, 2021 11:07 am Ответить с цитатой Вернуться к началу

В любом случае решить проблему с сигналами при помощи porfolio backtester невозможно.

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Astrobiolog



Зарегистрирован: 27.01.2013
Сообщения: 66

СообщениеДобавлено: Ср Янв 06, 2021 1:27 am Ответить с цитатой Вернуться к началу

000 писал(а):
В любом случае решить проблему с сигналами при помощи porfolio backtester невозможно.

Боюсь, ты ошибаешься. Возможно. Я решил. Но это очень сложно и нетривиально.
Посмотреть профиль Отправить личное сообщение
000
Site Admin


Зарегистрирован: 10.12.2007
Сообщения: 9106

СообщениеДобавлено: Ср Янв 06, 2021 7:05 am Ответить с цитатой Вернуться к началу

Делись.

_________________
ceterum censeo carthaginem esse delendam
Удачи. Олег.
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Astrobiolog



Зарегистрирован: 27.01.2013
Сообщения: 66

СообщениеДобавлено: Ср Янв 06, 2021 9:45 am Ответить с цитатой Вернуться к началу

000 писал(а):
Делись.

Я тоже несколько лет уже назад попытался пойти по пути sigScaleIn/sigScaleOut в low-level CBT.

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

Лучше и проще присваивать идентификаторы вообще каждому входу "вручную", если можно так сказать, из первой фазы во вторую (например через переменную sig.Score, есть и еще варианты - внимательно RTFM) и отслеживать судьбу каждого входа отдельно в CBT low-level.

Надеюсь, понятно, что речь идет о множественных входах-выходах (доливках-отливках по одному и тому же тикеру) это вообще-то тождественно sigScaleIn/Out, но однако так, что все работает как песня.

Надеюсь, то, что вышенаписано понятно ?
Посмотреть профиль Отправить личное сообщение
Показать сообщения:      
Начать новую тему  Ответить на тему


 Перейти:   



Следующая тема
Предыдущая тема
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете вкладывать файлы
Вы не можете скачивать файлы


Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme :: Часовой пояс: GMT + 3

File Attachment © by Meik Sievertsen