Чтобы напрямую ответить на ваш вопрос, установив .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
включают транзакционные издержки через аргумент TxnFees
(а ruleSignal
является аргументом 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