Пирамидинг в Амиброкере

Опубликовано в AmiBroker

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

Другой вариант - усреднение цены входа путем увеличения позиции при встречном движении рынка (метод мартингейла).

Как реализовать подобные алгоритмы в амиброкере?

Существует стандартный массив PositionSize. Если его заполнить цифрами, равными стоимости контрактов/акций, то в момент появления сигналов Buy, Sell, Short и Cover амиброкер будет соответствующим образом изменять размер своей виртуальной позиции.

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

 

СИНТАКСИС SetPositionSize( size, method )
ВОЗВРАЩАЕТ Массив
ОПИСАНИЕ Функция позволяет управлять размером позиции разными способами взависимости от параметра method.

Параметры:

size (Массив)     описывает требуемый размер позиции

method (Массив) задает интерпретацию

  • spsValue (=1) - долларовая стоимость
  • spsPercentOfEquity (=2) - Размер, выраженный как процент от уровня капитала (размер должен быть от .. 100 (для обычных счетов) или .1000 по маржинальным счетам)
  • spsShares (=4) - объём в контрактах или акциях (size должен быть > 0 )
  • spsPercentOfPosition (=3) - размер, выраженный в процентах от текущей позиции (только для SCALING IN или SCALING OUT)
  • spsNoChange (=0) - ничего не менять

Дополнительные возможности (совместимость с PositionSize)

  • значения ниже -2000 задают количество акций,
  • значения между -2000 and -1000 задают % от текущей позиции
  • values between -1000 and 0 задают % капитала
  • значения выше 0 задают долларовую

 Разработчик настоятельно рекомендует использовать механизм SetPositionSize вместо массива SetPosition.

 


Как применять?

  

Две специальные константы: sigScaleIn / sigScaleOut. Нужны для того, чтобы рассказать бектестеру, что нужно увеличить или уменьшить позицию

 

Все что требуется сделать для реализации изменяемого размера позиции, заключается в следующем:

  • Задайте переменной BUY / SHORT значение sigScaleIn, если хотите увеличить длинные / короткие позиции
  • Задайте переменной BUY / SHORT значение sigScaleOut, если хотите уменьшить длинные / короткие позиции

 

Масштабирование размера определяется переменной PositionSize, которая в случае масштабирования определяет не абсолютные значения позиции, а их изменение.

 

ВАЖНО: Обратите внимание, что backtester рассматривает последовательность изменений объема позиций (scale-in/out) как одну сделку (т.е. покажет одну строку в списке сделок бектестера). Единственная разница по сравнению с простой торговлей является то, что он будет рассчитывать среднюю цену входа и выхода. Комиссия, конечно, посчитается правильно, каждое изменение позиции будет сопровождаться комиссионными расходами.  

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

Можно включить подробный режим прямо из скрипта:

SetOption("PortfolioReportMode",1);


Примеры 



1. каждый месяц покупаем акции на одну и ту же сумму

FixedDollarAmount = 500
MonthBegin = 
Month() != RefMonth(), -1 ); 

FirstPurchase = 
Cum( MonthBegin ) == 1

Buy = IIf( FirstPurchase, 1// True (or 1) represents regular buy signal 
      IIf( MonthBegin, sigScaleIn// each month increase position 
           0 ) ); // otherwise no signal 

Sell = 0// we do not sell 
PositionSize = FixedDollarAmount;

2. Упрощенная формула, потому что Amibroker рассматривает первый sigScaleIn как Buy в любом случае

FixedDollarAmount = 500
MonthBegin = 
Month() != RefMonth(), -1 ); 

FirstPurchase = 
Cum( MonthBegin ) == 1

Buy = IIf( MonthBegin, sigScaleIn0 ); // ежемесячно увеличиваем позицию

Sell = 0// никогда не продаём

PositionSize = FixedDollarAmount;

 
3. Увеличение позиции, когда прибыли от торговли без пирамидинга становится больше, чем 5% и уменьшение позиции, когда потери больше, чем 5%
// percent equity change threshold when pyramiding is performed 
PyramidThreshold = 5

// regular trading rules (no pyramiding) 
Buy = CrossMACD(), Signal() ); 
Sell = CrossSignal(), MACD() ); 

e = 
Equity(1); // generate equity without pyramiding effect 

PcntProfit = 
100 * ( e - ValueWhenBuy, e ) )/ValueWhenBuy, e ); 

InTrade = 
FlipBuySell ); 

// ExRem is used here to ensure that scaling-in/out occurs 
// only once since trade entry 
DoScaleIn = 
ExRem( InTrade AND PcntProfit > PyramidThreshold, Sell ); 
DoScaleOut = 
ExRem( InTrade AND PcntProfit < -PyramidThreshold, Sell ); 

// modify rules to handle pyramiding 
Buy = Buy + sigScaleIn * DoScaleIn + sigScaleOut * DoScaleOut; 

PositionSize = IIf( DoScaleOut, 5001000 ); // enter and scale-in size $1000, scale-out size: $500
 
3. Частичный выход (scaling out) по достижению уровня взятия прибыли. Уменьшается позиция на 50% не первом тейк-уровне и на 50% на втором. По трейлинг стопу закрывается сразу вся позиция
Buy = CrossMAC10 ), MAC50 ) ); 
Sell = 0

FirstProfitTarget = 10// profit 
SecondProfitTarget = 
20// in percent 
TrailingStop = 
10// also in percent 

priceatbuy=
0
highsincebuy = 
0

exit = 
0

for( i = 0; i < BarCount; i++ ) 

   
if( priceatbuy == 0 AND Buy[ i ] ) 
    { 
       priceatbuy = 
BuyPrice[ i ]; 
    } 

   
if( priceatbuy > 0 ) 
    { 
       highsincebuy = 
MaxHigh[ i ], highsincebuy ); 

      
if( exit == 0 AND 
          
High[ i ] >= ( 1 + FirstProfitTarget * 0.01 ) * priceatbuy ) 
       { 
         
// first profit target hit - scale-out 
         exit = 
1
         
Buy[ i ] = sigScaleOut
       } 

      
if( exit == 1 AND 
          
High[ i ] >= ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy ) 
       { 
         
// second profit target hit - exit 
         exit = 
2
         
SellPrice[ i ] = MaxOpen[ i ], ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy ); 
       } 

      
ifLow[ i ] <= ( 1 - TrailingStop * 0.01 ) * highsincebuy ) 
       { 
         
// trailing stop hit - exit 
         exit = 
3;    
         
SellPrice[ i ] = MinOpen[ i ], ( 1 - TrailingStop * 0.01 ) * highsincebuy ); 
       } 

      
if( exit >= 2 ) 
       { 
         
Buy[ i ] = 0
         
Sell[ i ] = exit + 1// mark appropriate exit code 
         exit = 
0
         priceatbuy = 
0// reset price 
         highsincebuy = 
0
       } 
    } 


SetPositionSize50spsPercentOfEquity ); 
SetPositionSize50spsPercentOfPosition * ( Buy == sigScaleOut ) ); // scale out 50% of position



Можно ли такие формулы превращать в полноценного робота, выставляющего заявки в соответствии с алгоритмом и изменяя размер позиции? Да, можно. В частности,это можно реализовать с помощью AmiSharp.

Комментарии   

# Ambrosiy 26.03.2017 18:25
Подскажите пожалуйста, как амик будит себя вести если первый и второй уровень будит взят одной свечой.
Как то так

if( exit == 0 AND High[ i ] >= ( 1 + FirstProfitTarg et * 0.01 ) * priceatbuy )
{
// first profit target hit - scale-out
exit = 1;
Buy[ i ] = sigScaleOut;
BuyPrice[ i ] = ( 1 + FirstProfitTarg et * 0.01 ) * priceatbuy;
}

if( exit == 1 AND High[ i ] >= ( 1 + SecondProfitTar get * 0.01 ) * priceatbuy )
{
// second profit target hit - scale-out
exit = 2;
Buy[ i ] = sigScaleOut;
BuyPrice[ i ] = ( 1 + SecondProfitTar get * 0.01 ) * priceatbuy;
}


Одна свеча один параметр, получается первый уровень будит проигнорирован?
Если да, какой способ применим?
Ответить | Ответить с цитатой | Цитировать
# admin 26.03.2017 19:24
Конечно. На одной свече сделать два одинаковых сигнала нельзя.

Расширяйте логику. Если сработал Профит 2, значит профит1 тоже должен существовать и его надо исполнять.
Ответить | Ответить с цитатой | Цитировать

Добавить комментарий


Защитный код
Обновить