R: Quantstrat, как совершить сделку для полного капитала в портфеле?

Я все еще играю с примером Quantstrat Гая Йоллинза. В этом примере он покупает 1000 акций SPY, когда она пересекает свою 10-дневную MA. Поскольку мы определяем начальный капитал, можно ли всегда покупать всю сумму портфеля, а не только 900 акций? «все» не работало для входа, только для выхода.

if (!exists('.blotter')) .blotter <- new.env()
if (!exists('.strategy')) .strategy <- new.env()
if (!exists('.instrument')) .instrument <- new.env()
currency("USD")
stock("SPY",currency="USD",multiplier=1)
ls(envir=FinancialInstrument:::.instrument)


initDate <- '1997-12-31'
startDate <- '1998-01-01'
endDate <- '2013-07-31'
initEq <- 1e6
Sys.setenv(TZ="UTC")
getSymbols('SPY', from=startDate, to=endDate, adjust=T)
SPY=to.monthly(SPY, indexAt='endof')
SPY$SMA10m <- SMA(Cl(SPY), 10)

# inz portfolio, account
qs.strategy <- "qsFaber"
rm.strat(qs.strategy) # remove strategy etc. if this is a re-run
initPortf(qs.strategy,'SPY', initDate=initDate)
initAcct(qs.strategy,portfolios=qs.strategy, initDate=initDate, initEq=initEq)


initOrders(portfolio=qs.strategy,initDate=initDate)
# instantiate a new strategy object
strategy(qs.strategy,store=TRUE)
add.indicator(strategy = qs.strategy, name = "SMA",
              arguments = list(x = quote(Cl(mktdata)), n=10), label="SMA10")
add.signal(qs.strategy,name="sigCrossover",
           arguments = list(columns=c("Close","SMA10"),relationship="gt"),
           label="Cl.gt.SMA")
add.signal(qs.strategy,name="sigCrossover",
           arguments = list(columns=c("Close","SMA10"),relationship="lt"),
           label="Cl.lt.SMA")

add.rule(qs.strategy, name='ruleSignal',
         arguments = list(sigcol="Cl.gt.SMA", sigval=TRUE, orderqty=900,
                          ordertype='market', orderside='long', pricemethod='market'),
         type='enter', path.dep=TRUE)
add.rule(qs.strategy, name='ruleSignal',
         arguments = list(sigcol="Cl.lt.SMA", sigval=TRUE, orderqty='all',
                          ordertype='market', orderside='long', pricemethod='market'),
         type='exit', path.dep=TRUE)


out <- applyStrategy(strategy=qs.strategy , portfolios=qs.strategy)
updatePortf(qs.strategy)
updateAcct(qs.strategy)
updateEndEq(qs.strategy)

myTheme<-chart_theme()
myTheme$col$dn.col<-'lightblue'
myTheme$col$dn.border <- 'lightgray'
myTheme$col$up.border <- 'lightgray'
# plot performance
chart.Posn(qs.strategy, Symbol = 'SPY', Dates = '1998::',theme=myTheme)
plot(add_SMA(n=10,col=4, on=1, lwd=2))

person MichiZH    schedule 21.10.2013    source источник


Ответы (3)


Вы не можете использовать orderqty="all" для входов, потому что "all" относится к текущему размеру позиции (т. е. когда вы хотите закрыть всю позицию).

Можно приобрести сумму, равную общему доступному капиталу портфеля, но вы должны определить собственную функцию размера ордера. И эта функция обязательно должна была бы отметить книгу (используя updatePortf), чтобы определить сумму доступного капитала.

person Joshua Ulrich    schedule 21.10.2013
comment
Спасибо за ваш ответ. У вас есть ссылка на пример, как это сделать? - person MichiZH; 21.10.2013
comment
@MichiZH: Нет, не знаю. - person Joshua Ulrich; 21.10.2013
comment
Но какой-нибудь намек на то, как я могу получить текущую эквити, которую я могу использовать в этих правилах? Я имею в виду, что такая функция определения размера пользовательского ордера должна иметь доступ к текущему капиталу... - person MichiZH; 21.10.2013
comment
@MichiZH: я уже говорил тебе это. Используйте updatePorf, чтобы отметить книгу. - person Joshua Ulrich; 21.10.2013
comment
Извините, я все еще новичок в R и особенно в quantstrat, quantmod и т. д., и кривая обучения довольно крутая. Извините, что не понял с первого раза и до сих пор не знаю, как это реализовать. - person MichiZH; 21.10.2013

Вот игрушечный пример, который достигает того, чего вы хотите.

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

Взгляните на аргументы функции ruleSignal (например, formals(ruleSignal) и ?ruleSignal).

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

Вы изменяете соответствующие параметры в add.rule, чтобы ввести размер ордеров (при входных сделках).

osFUN_all_eq <- function (data, timestamp, orderqty, ordertype, orderside, equity, portfolio, symbol, ruletype, ..., initEq) {
    datePos <- format(timestamp,"%Y-%m-%d")

    updatePortf(Portfolio = portfolio, Symbol = symbol, Dates = paste0(start(data), "/", datePos))

    trading_pl <- sum(.getPortfolio(portfolio)$summary$Net.Trading.PL)
    # The total equity in the strategy for this symbol (and this symbol only in isolation always, as this is how quantstrat by default works with applyStrategy)
    equity <- initEq + trading_pl
    ClosePrice <- getPrice(data, prefer = "Close")[datePos]
    UnitSize <- as.numeric(trunc(equity / ClosePrice))
    UnitSize <- osMaxPos(data, timestamp, UnitSize, ordertype, orderside, portfolio, symbol, ruletype, digits=0)
    UnitSize
}





library(quantstrat)

currency("USD")
stock("SPY",currency="USD",multiplier=1)


initDate <- '1997-12-31'
startDate <- '1998-01-01'
endDate <- '2013-07-31'
initEq <- 1e6
Sys.setenv(TZ="UTC")
getSymbols('SPY', from=startDate, to=endDate, adjust=T)
SPY=to.monthly(SPY, indexAt='endof')
SPY$SMA10m <- SMA(Cl(SPY), 10)


qs.strategy <- "qsFaber"
rm.strat(qs.strategy) # remove strategy etc. if this is a re-run
initPortf(qs.strategy,'SPY', initDate=initDate)
initAcct(qs.strategy,portfolios=qs.strategy, initDate=initDate, initEq=initEq)


initOrders(portfolio=qs.strategy,initDate=initDate)
# instantiate a new strategy object
strategy(qs.strategy,store=TRUE)


# Specify the max quantity you could hold in the SPY instrument.  Here we simply assume 1e5 units. You could reduce this number to limit the exposure
max_qty_traded <- 1e5
addPosLimit(qs.strategy, "SPY", timestamp = startDate, maxpos = max_qty_traded)

add.indicator(strategy = qs.strategy, name = "SMA",
              arguments = list(x = quote(Cl(mktdata)), n=10), label="SMA10")
add.signal(qs.strategy,name="sigCrossover",
           arguments = list(columns=c("Close","SMA10"),relationship="gt"),
           label="Cl.gt.SMA")
add.signal(qs.strategy,name="sigCrossover",
           arguments = list(columns=c("Close","SMA10"),relationship="lt"),
           label="Cl.lt.SMA")

add.rule(qs.strategy, name='ruleSignal',
         arguments = list(sigcol="Cl.gt.SMA",
                          sigval=TRUE,
                          orderqty = 1, # the acutal orderqty size becomes redundant when supplying a function to the argument `osFUN`
                          osFUN = osFUN_all_eq,
                          ordertype='market', orderside='long', pricemethod='market'),
         type='enter', path.dep=TRUE)


add.rule(qs.strategy, name='ruleSignal',
         arguments = list(sigcol="Cl.lt.SMA",
                          sigval=TRUE,
                          orderqty='all', # flatten all open long positions
                          ordertype='market',
                          orderside='long',
                          pricemethod='market'),
                          type='exit',
         path.dep=TRUE)


# supply initEq parameter and its value, which pass through to `osFUN`
out <- applyStrategy(strategy=qs.strategy , portfolios=qs.strategy, initEq=initEq)
updatePortf(qs.strategy)
updateAcct(qs.strategy)
updateEndEq(qs.strategy)

myTheme<-chart_theme()
myTheme$col$dn.col<-'lightblue'
myTheme$col$dn.border <- 'lightgray'
myTheme$col$up.border <- 'lightgray'
# plot performance
chart.Posn(qs.strategy, Symbol = 'SPY', Dates = '1998::',theme=myTheme)
plot(add_SMA(n=10,col=4, on=1, lwd=2))

Есть несколько вещей, которые вы должны учитывать в функции определения размера ордера:

1) Если у вас уже есть открытая позиция, хотите ли вы разрешить «стекирование»/пирамидирование позиций на определенной стороне? Например, если вы хотите иметь только одну позицию, в которую вы больше не вносите вклад, вы можете включить getPosQty(qs.strategy, "SPY", timestamp) в свой osFUN и вернуть 0, если текущая удерживаемая позиция не равна 0.

2) Вы хотите максимальный размер сделки? Это может быть обработано с помощью addPosLimit(), как это было сделано в этом примере выше.

person FXQuantTrader    schedule 20.04.2019

Я знаю, что этот вопрос был опубликован давно, но проверьте пакет «IKTrading» и функцию определения размера ордера «osMaxDollar». Вот сообщение в блоге по теме; когда вы используете эту функцию размера ордера, вы можете установить долларовую стоимость каждой сделки и общую позицию.

https://quantstrattrader.wordpress.com/2014/08/29/comparing-atr-order-sizing-to-max-dollar-order-sizing/

person kng229    schedule 30.07.2015