R: Множитель Quantstrat TxnFees

Я пытаюсь запустить стратегию обратного тестирования в пакете R Quantstrat. Инструмент представляет собой фьючерс на пшеницу и котируется в центах США. Размер контракта составляет 5000 бушелей. Поэтому я добавил следующий код.

future(symbols, 
      currency = "USD",
      tick_size = 0.25,
      multiplier = 50) 

Однако при запуске модели кажется, что прибыль слишком мала, и она приносит убыток, что побудило меня посмотреть, как рассчитываются комиссии за транзакции в пакете блоттера как показано в этом коде на github.

#' @param ConMult Contract/instrument multiplier for the Symbol if it is not defined in an instrument specification

Означает ли это, что когда я указываю .txnfees <- -10, налоговый сбор составляет 50 * -10 = -500, и в этом случае я должен указать TxnFees равным -0,2. Как указать фиксированную сумму в заказе?


person youjustreadthis    schedule 13.07.2017    source источник


Ответы (1)


Чтобы напрямую ответить на ваш вопрос, установив .txnfees <- -10 в ruleSignal, стоимость транзакции для сделки будет равна -10, независимо от количества сделки. Множители в контрактах, определенных FinancialInstrument, не влияют напрямую на расчет стоимости сделки. Вот как вы можете добиться того, чего ожидаете...

Сначала немного предыстории: исходный код для addTxn в blotter — это место, где транзакционные издержки вступают в игру в quantstrat бэктестах, которые вы правильно определили. Вы можете передать TxnFees как (неположительное) числовое значение или строку символов, которая является именем функции, определяющей, как рассчитываются сборы. Посмотрите внимательно, и вы увидите, что TxnQty, TxnPrice, Symbol — это все аргументы, которые передаются функции TxnFee. см. эту часть кода в addTxn:

if (is.function(TxnFees)) {
      txnfees <- TxnFees(TxnQty, TxnPrice, Symbol) 
    } else {
      txnfees<- as.numeric(TxnFees)
    }

В quantstrat аргументы ruleSignal включают транзакционные издержки через аргумент TxnFeesruleSignal является аргументом add.rule). Но вы можете передать пользовательскую функцию (указав ее имя в виде строки в аргументе ruleSignal), которая будет моделировать способ, который вам может понравиться.

Если вы посмотрите в тот же исходный файл блоттера, который вы связали, есть пример функции транзакционных издержек (посмотрите на модульные тесты блоттера, и вы увидите примеры того, как эта функция транзакционных издержек используется):

pennyPerShare <- function(TxnQty, ...) {
    return(abs(TxnQty) * -0.01)
}

Ниже приведен еще один полностью воспроизводимый пример того, как вы можете смоделировать комиссионные, являющиеся функцией количества сделок, и просто для демонстрации я использую аргумент множителя контракта из объекта stock вместо объекта future, но, очевидно, та же самая логика применима и для любой тип инструмента. В приведенном ниже примере за каждую транзакцию взимается комиссия в размере 1,5% от проданного количества в качестве стоимости транзакции. Вы также можете сделать сборы функцией TxnPrice, что является еще одним аргументом функции.

#---------------------------------------------------------------
# Define the transaction cost function
txnFUN <- function(TxnQty, TxnPrice, Symbol, pct = 0.015) {
  multiStock <- getInstrument(Symbol)$multiplier
  # Do something with multiStock, here it is equal to 1, so it's effectively meaningless but shows how you could go about using it.

  fees <- abs(TxnQty) * pct * multiStock
  # Fees are a negative deduction for the trade:
  if (fees > 0) fees <- -fees

  fees
}

#-------------------------------------------------------------------------------------


library(quantstrat)


suppressWarnings(rm("order_book.RSI",pos=.strategy))
suppressWarnings(rm("account.RSI","portfolio.RSI",pos=.blotter))
suppressWarnings(rm("account.st","portfolio.st","stock.str","stratRSI","startDate","initEq",'start_t','end_t'))


strategy.st <- "RSI"

stratRSI <- strategy(strategy.st, store = TRUE)


add.indicator(strategy = strategy.st, name = "RSI", arguments = list(price = quote(getPrice(mktdata))), label="RSI")
add.signal(strategy = strategy.st, name="sigThreshold",arguments = list(threshold=70, column="RSI",relationship="gt", cross=TRUE),label="RSI.gt.70")

add.signal(strategy = strategy.st, name="sigThreshold",arguments = list(threshold=30, column="RSI",relationship="lt",cross=TRUE),label="RSI.lt.30")


add.rule(strategy = strategy.st, name='ruleSignal', arguments = list(sigcol="RSI.lt.30", sigval=TRUE, orderqty= 100, TxnFees="txnFUN", ordertype='market', orderside='long', pricemethod='market', replace=FALSE, osFUN=osMaxPos), type='enter', path.dep=TRUE)
add.rule(strategy = strategy.st, name='ruleSignal', arguments = list(sigcol="RSI.gt.70", sigval=TRUE, orderqty='all', TxnFees="txnFUN", ordertype='market', orderside='long', pricemethod='market', replace=FALSE), type='exit', path.dep=TRUE)


currency("USD")
symbols = c("SPY")
stock.str = symbols

    startDate <- "1987-01-01"
    getSymbols(stock.str,from=startDate, to= Sys.Date())

for(symbol in symbols){
    stock(symbol, currency="USD",multiplier=1)
}
SPY <- SPY["2015/"]


startDate='2005-12-31'
initEq=100000
port.st<-'RSI'

initPortf(port.st, symbols=symbols)
initAcct(port.st, portfolios=port.st, initEq=initEq)
initOrders(portfolio=port.st)
for(symbol in symbols){ addPosLimit(port.st, symbol, startDate, 300, 3 ) }

applyStrategy(strategy=strategy.st , portfolios=port.st, parameters=list(n=2) ) 

updatePortf(Portfolio=port.st,Dates=paste('::',as.Date(Sys.time()),sep=''))

Убедитесь, что комиссия соответствует ожидаемому количеству проданного товара:

tail(getTxns(port.st, "SPY"), 15)
#                     Txn.Qty Txn.Price Txn.Fees Txn.Value Txn.Avg.Cost Net.Txn.Realized.PL
# 2017-03-28 20:00:00    -100  234.3969     -1.5 -23439.69     234.3969            178.6209
# 2017-04-05 20:00:00     100  234.2974     -1.5  23429.74     234.2974             -1.5000
# 2017-04-11 20:00:00     100  232.8943     -1.5  23289.43     232.8943             -1.5000
# 2017-04-20 20:00:00    -200  233.4515     -3.0 -46690.31     233.4515            -31.8605
# 2017-05-14 20:00:00     100  239.1338     -1.5  23913.38     239.1338             -1.5000
# 2017-05-15 20:00:00    -100  238.9149     -1.5 -23891.49     238.9149            -23.3933
# 2017-05-17 20:00:00     100  235.6210     -1.5  23562.10     235.6210             -1.5000
# 2017-05-22 20:00:00    -100  238.8851     -1.5 -23888.51     238.8851            324.9084
# 2017-06-12 20:00:00     100  243.3632     -1.5  24336.32     243.3632             -1.5000
# 2017-06-13 20:00:00    -100  243.0547     -1.5 -24305.47     243.0547            -32.3502
# 2017-06-27 20:00:00     100  243.4900     -1.5  24349.00     243.4900             -1.5000
# 2017-06-29 20:00:00     100  241.8000     -1.5  24180.00     241.8000             -1.5000
# 2017-07-05 20:00:00    -200  240.5500     -3.0 -48110.00     240.5500           -422.0002
# 2017-07-06 20:00:00     100  242.1100     -1.5  24211.00     242.1100             -1.5000
# 2017-07-12 20:00:00    -100  244.4200     -1.5 -24442.00     244.4200            229.4997
person FXQuantTrader    schedule 16.07.2017
comment
@Stat Оба вопроса должны решаться следующим образом: посмотрите на blotter::addTxn, и вы увидите, что TxnFees предоставляется как функция, там есть жестко запрограммированный вызов txnfees <- TxnFees(TxnQty, Txnprice, Symbol), так что нет, вы не можете в текущий код предоставляет список аргументов для TxnFees. Но если вы хотите указать произвольные параметры, вы можете просто создать среду (в .GlobalEnv), содержащую параметры или данные, к которым вы получите доступ в определенной вами функции TxnFees (которая будет вызываться в addTxn). - person FXQuantTrader; 12.12.2020
comment
Если неясно, как передать параметры в среду функции, пример того, как это сделать, приведен quantstrat::getOrderBook, где .strategy — это среда, в которой хранятся внешние параметры/данные. - person FXQuantTrader; 12.12.2020
comment
Просто для большей ясности я бы добавил, что пользовательская функция pennyPerShare <- function(TxnQty, ...) работает, потому что при вызове TxnFees(TxnQty, Txnprice, Symbol) аргументы TxnPrice, Symbol упаковываются в ... . - person FXQuantTrader; 12.12.2020
comment
Большое спасибо. Действительно ценю это. Извините ... Я случайно удалил свой вопрос выше, так как нашел ответ на свой 2-й вопрос, когда вернулся к нему. Я думал, ты еще не ответил. Прости за это. Для полноты картины я спросил у FXQuantTrader Q1: можно ли добавить аргумент txnFUN, например. pct = 0,015 к правилу add.rule и Q2, откуда в txnFUN берутся TxnQty, Txnprice. - person Stat; 12.12.2020