R: Quantstrat how to make a transaction for comple

2020-07-17 06:21发布

问题:

I'm still playing around with Guy Yollins quantstrat example. In this example he buys 1000 shares of the SPY when it crosses its 10 day MA. Since we define an initial equity, is it possible to always buy for the whole portfolio amount and not just 900 shares? 'all' didn't work for the enter, just the exit..

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))

回答1:

You cannot use orderqty="all" on entries because "all" refers to the current position size (i.e., when you want to exit the entire position).

It's possible to purchase an amount equal to the total available portfolio equity, but you have to define a custom order sizing function. And that function would necessarily have to mark the book (using updatePortf) in order to determine the amount of available equity.



回答2:

I know this question was posted long ago, but check out package "IKTrading," and the order sizing function "osMaxDollar." Here's a blog post on the topic; when you use this order sizing function you can set the dollar value of each trade and the total position.

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



回答3:

Here is a toy example that achieves what you want.

You need to introduce an order sizing function.

Take a look at the arguments to the function ruleSignal (e.g. formals(ruleSignal) and ?ruleSignal).

You'll see there is an argument osFUN, which is where you can write your custom function that will determine how you order size.

You modify the appropriate parameters in add.rule to introduce ordersizing (on entry trades).

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))

There are a few things you should consider in an order sizing function:

1) If you already have a position open, do you want to permit "stacking"/pyramidying of positions on a particular side? For example, if you want to just have one position on, which you don't contribute further to, you could include getPosQty(qs.strategy, "SPY", timestamp) in your osFUN and return 0 if the current position held is not 0.

2) Do you want a max trade size? This can be handled using addPosLimit() as was done in this example above.



标签: r quantstrat