Вторая часть
Третья часть
Четвертая часть
Пятая часть
Шестая часть
Седьмая часть
Восьмая часть
Девятая часть
Десятая часть
Одиннадцатая часть
Двенадцатая часть
Из результатов, полученных в предыдущей части, ясно, что оптимальную величину стоп-лоссов необходимо подбирать так же, как оптимальные значения индикаторов. Этим мы и займемся сейчас.
Первая часть скрипта, где задаются первоначальные настройки, остается такой же, как в предыдущей части, поэтому здесь я ее для экономии места приводить не буду.
Однако при сохранении настроек в переменных вместо одного значения стоп-лосса в переменной .Stoploss хранится последовательность из 48 чисел от 0,005 до 0,03, то есть величина стоп-лосса варьируется от 0,5 до 3% от размера позиции.
# Сохраняем настройки в переменных
.fast <- 7
.slow <- 21
.orderqty <- 100
.txnfees <- -20
.StopLoss <- seq(0.005, 0.03, length.out = 48)
portfolio.st <- "Port.Luxor.Stop.Loss.Opt"
account.st <- "Acct.Luxor.Stop.Loss.Opt"
strategy.st <- "Strat.Luxor.Stop.Loss.Opt"
Далее стандартная инициализация объектов нашей стратегии:
# Удаляем остатки предыдущих запусков стратегий и очищаем значения нашего портфеля и счета
rm.strat(portfolio.st)
rm.strat(account.st)
# Инициализация портфеля
initPortf(name = portfolio.st,
symbols = symbols,
initDate = init_date)
# Инициализация счета
initAcct(name = account.st,
portfolios = portfolio.st,
initDate = init_date)
# Инициализация ордеров
initOrders(portfolio = portfolio.st,
initDate = init_date)
# Инициализация стратегии
strategy(strategy.st, store = TRUE)
Теперь добавляем сигналы:
# Сигнал на открытие длинной позиции
add.signal(strategy.st,
name = "sigCrossover",
arguments = list(columns = c("nFast", "nSlow"),
relationship = "gte"),
label = "long")
# Сигнал на открытие короткой позиции
add.signal(strategy.st,
name = "sigCrossover",
arguments = list(columns = c("nFast", "nSlow"),
relationship = "lt"),
label = "short")
И, наконец, правила, в том числе для стоп-лоссов:
# Правило открытия длинной позиции
add.rule(strategy.st,
name = "ruleSignal",
arguments = list(sigcol = "long",
sigval = TRUE,
replace = FALSE,
orderside = "long",
ordertype = "stoplimit",
prefer = "High",
TxnFees = .txnfees,
orderqty = +.orderqty,
osFUN = osMaxPos,
orderset = "ocolong"),
type = "enter",
label = "EnterLONG")
# Правило открытия короткой позиции
add.rule(strategy.st,
name = "ruleSignal",
arguments = list(sigcol = "short",
sigval = TRUE,
replace = FALSE,
orderside = "short",
ordertype = "stoplimit",
prefer = "Low",
TxnFees = .txnfees,
orderqty = -.orderqty,
osFUN = osMaxPos,
orderset = "ocoshort"),
type = "enter",
label = "EnterSHORT")
# Правило закрытия длинной позиции
add.rule(strategy.st,
name = "ruleSignal",
arguments = list(sigcol = "short",
sigval = TRUE,
replace = TRUE,
orderside = "long" ,
ordertype = "market",
TxnFees = .txnfees,
orderqty = "all",
orderset = "ocolong"),
type = "exit",
label = "Exit2SHORT")
# Правило закрытия короткой позиции
add.rule(strategy.st,
name = "ruleSignal",
arguments = list(sigcol = "long",
sigval = TRUE,
replace = TRUE,
orderside = "short",
ordertype = "market",
TxnFees = .txnfees,
orderqty = "all",
orderset = "ocoshort"),
type = "exit",
label = "Exit2LONG")
# Правила для стоп-лоссов
add.rule(strategy.st,
name = "ruleSignal",
arguments = list(sigcol = "long" ,
sigval = TRUE,
replace = FALSE,
orderside = "long",
ordertype = "stoplimit",
tmult = TRUE,
threshold = quote(.stoploss),
TxnFees = .txnfees,
orderqty = "all",
orderset = "ocolong"),
type = "chain",
parent = "EnterLONG",
label = "StopLossLONG",
enabled = FALSE)
add.rule(strategy.st,
name = "ruleSignal",
arguments = list(sigcol = "short",
sigval = TRUE,
replace = FALSE,
orderside = "short",
ordertype = "stoplimit",
tmult = TRUE,
threshold = quote(.stoploss),
TxnFees = .txnfees,
orderqty = "all",
orderset = "ocoshort"),
type = "chain",
parent = "EnterSHORT",
label = "StopLossSHORT",
enabled = FALSE)
Добавляем лимит позиции:
for(symbol in symbols){
addPosLimit(portfolio = portfolio.st,
symbol = symbol,
timestamp = init_date,
maxpos = .orderqty)
}
Добавление распределения
Мы снова используем add.distribution, чтобы назначить наш вектор .StopLoss в качестве значений для цепочек правил StopLossLONG и StopLossSHORT.
# Добавление распределения
add.distribution(strategy.st,
paramset.label = "StopLoss",
component.type = "chain",
component.label = "StopLossLONG",
variable = list(threshold = .StopLoss),
label = "StopLossLONG")
add.distribution(strategy.st,
paramset.label = "StopLoss",
component.type = "chain",
component.label = "StopLossSHORT",
variable = list(threshold = .StopLoss),
label = "StopLossSHORT")
Добавление ограничения распределения
Мы также можем задать ограничение распределения, чтобы параметры StopLossLONG и StopLossSHORT оставались одинаковыми.
# Добавляем ограничение для распределений
add.distribution.constraint(strategy.st,
paramset.label = "StopLoss",
distribution.label.1 = "StopLossLONG",
distribution.label.2 = "StopLossSHORT",
operator = "==",
label = "StopLoss")
Далее активируем наши правила:
# Активация правил
enable.rule(strategy.st, 'chain', 'StopLoss')
Для ускорения процесса можно активировать поддержку параллельных вычислений:
# Активация параллельных вычислений
library(parallel)
if( Sys.info()['sysname'] == "Windows") {
library(doParallel)
registerDoParallel(cores=detectCores())
} else {
library(doMC)
registerDoMC(cores=detectCores())
}
И запускаем оптимизацию:
# Запуск оптимизации
results <- apply.paramset(strategy.st,
paramset.label = "StopLoss",
portfolio.st = portfolio.st,
account.st = account.st,
nsamples = .nsamples,
verbose = TRUE)
Теперь сохраняем результаты оптимизации в переменной tS:
tS <- results$tradeStats
Если мы использовали ограничения распределения, то есть величина стоп-лосса для длинный и коротких позиций одинакова, тогда для визуализации результатов можно просто построить график зависимости прибыли от величины стоп-лосса:
# График зависимости прибыли от величины стоп-лосса
ggplot(data = tS, aes(x = StopLossLONG, y = End.Equity)) +
geom_line(color = "blue", size = 2) +
xlab("Стоп-лосс") +
ylab("Чистая прибыль") +
ggtitle("Зависимость прибыли от величины стоп-лосса")
# чистая прибыль/убыток
z <- tapply(X = tS[,"End.Equity"], INDEX = list(Long=tS[,1], Short = tS[,2]), FUN = sum)
x <- as.numeric(rownames(z))
y <- as.numeric(colnames(z))
filled.contour(x = x, y = y, z = z, color = heat.colors, xlab="StopLoss Long", ylab = "StopLoss Short")
title("Чистая прибыль")
# максимальная просадка
z <- tapply(X = tS[,"Max.Drawdown"], INDEX = list(Long=tS[,1], Short=tS[,2]), FUN = sum)
x <- as.numeric(rownames(z))
y <- as.numeric(colnames(z))
filled.contour(x = x, y = y, z = z, color = heat.colors, xlab = "StopLoss Long", ylab = "StopLoss Short")
title("Максимальная просадка")
Если ограничения не активировались, перебираются все возможные пары значений стоп-лоссов для длинных и коротких значений, и процесс занимает намного больше времени. В данном случае для визуализации результатов оптимизации лучше всего подходят тепловые карты, как и в случае оптимизации величин индикаторов.
Можно также построить гистограмму распределения прибылей и убытков:
# Построение гистограммы распределения прибылей
profit_gr <- ggplot(tS, aes(x=End.Equity)) +
geom_density(fill = "lightblue",color="white")
profit_gr + xlab("Общая прибыль") +
ggtitle("Распределение прибылей стратегии пересечения двух скользящих средних")
Комментариев нет:
Отправить комментарий