Назад

Тестирование алгоритмических торговых стратегий в "R"

Кто не знает, среда R предлагает широкие возможности для работы с большими объемами данных, техническими индикаторами, и хорошо подходит для тестирования автоматических стратегий с тем, чтобы в дальнейшем решить, стоит ли программировать торгового робота на данной стратегии.

Ниже я предлагаю ознакомиться с этими возможностями на примере простой свечной стратегии:

Сигнал на покупку1: Если три предыдущих свечи были красные и текущее закрытие ниже открытия последней зеленой свечи

Сигнал на покупку2: Если текущая свеча красная и ее тело в три раза больше максимального тела из трех предыдущих свечей

Оба сигнала фильтруются по SMA. Покупка идет, только если цена ниже SMA от последних десяти свечей.

Сигналы на продажу - аналогичные с точностью до наоборот, но использоваться не будут, т.к. стратегия тестируется для биржи binance, где шортов нет.

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

Исходные данные буду брать из гугл-таблиц, куда предварительно помещу их из сервиса bitcoincharts.com

Для начала нам нужно установить R. Берем его с www.r-project.org

Далее устанавливаем в R две библиотеки: для работы с листами гугл и библиотеку технического анализа

install.packages('googlesheets')

library('googlesheets')

install.packages("TTR")

library("TTR")

К слову, можно получить набор свечей любым другим способом: через файл CSV, через локальную базу SQL. Соответствующие библиотеки в R имеются.

gs_read("https://docs.google.com/spreadsheets/d/1zlNPnPCI_KFTr5wNX6XRjsLicnWgTSgwuoQxOKAM7kw/edit#gid=0")

gs_ls()

be <- gs_title("BTCUSDT 1H")

# list worksheets

gs_ws_ls(be)

# get Westminster voting

west <- gs_read(ss=be, ws = "Sheet1", skip=0)

wdf <- as.data.frame(west)

Теперь у нас есть часовые свечи за три последних месяца (или сколько у вас в файле) в наборе данных.

Используемые названия колонок:

Timestamp - время свечи

Open - цена открытия

Close - цена закрытия

Первым делом добавляем индикаторные и вспомогательные колонки

#знак свечи

wdf$bar <- as.integer(wdf$Close >= wdf$Open) - as.integer(wdf$Close <=wdf$Open)

wdf$body <- abs(wdf$Close - wdf$Open)

#цена открытия последней бычьей и медвежьей свечи

wdf$openbull <- 0

for(i in 2:nrow(wdf)){wdf$openbull[i] = ifelse (wdf$bar[i]==1 && wdf$bar[i-1]!=1, wdf$open[i], wdf$openbull[i-1]) }

 wdf$openbear <- 0

for(i in 2:nrow(wdf)){wdf$openbear[i] = ifelse (wdf$bar[i]==-1 && wdf$bar[i-1]!=-1, wdf$Open[i], wdf$openbear[i-1]) }

 # для вычисления цвета трех последних свечей

wdf$barsma3 <- 0

for(i in 4:nrow(wdf)){wdf$barsma3[i] = (wdf$bar[i-2] + wdf$bar[i-1] +wdf$bar[i]) / 3 }

 #среднее тело свечи для отбраковки откровенно маленьких

wdf$abody <- SMA(wdf$body,10)

#SMA для фильтрации сигналов

wdf$sma10 <- SMA(wdf$Close,10)

#максимум тела трех предыдущих свечей

wdf$body3 <- 0

for(i in 4:nrow(wdf)){wdf$body3[i] <- max(c(wdf$body[i-1], wdf$body[i-2], wdf$body[i-3]))

#Добавляем сигналы и заполняем итерационно-вычисляемые колонки:

# сигналы на покупку и продажу

wdf$up1 <- (wdf$barsma3 == -1) & (wdf$Close < wdf$openbull) & wdf$body > wdf$abody / 5 & (wdf$Close < wdf$sma10)

wdf$up2 <- wdf$bar == -1 & wdf$body > wdf$body3 * 3 & wdf$body > wdf$abody / 5 & (wdf$Close < wdf$sma10)

wdf$dn1 <- wdf$barsma3 ==1 & (wdf$Close > wdf$openbear) & ( wdf$position == 0 || wdf$Close > wdf$pos_price ) & wdf$body > wdf$abody / 5

wdf$dn2 <- wdf$bar == 1 & wdf$body > wdf$body3 * 3 & wdf$body > wdf$abody / 5 & (wdf$Close > wdf$sma10)

# вычисление позиции (0 - не в позиции, 1 - позиция long)

# pos_close - сигнал на закрытие позиции

# balance - баланс. За начало берется число 1000


for(i in 1:nrow(wdf)){

wdf$position[i] <- ifelse( i==1, 0, ifelse( wdf$pos_close[i-1], 0, ifelse((wdf$up1[i-1] || wdf$up2[i-1]) & ( wdf$position[i-1]==0 || wdf$Close[i-1] < wdf$pos_price[i-1] ) , 1, ifelse(wdf$dn1[i-1] || wdf$dn2[i-1], -1, wdf$position[i-1]))))

wdf$position[i] <- ifelse( is.na(wdf$position[i]), 0, wdf$position[i])

wdf$pos_price[i] <- ifelse( i==1, 0, ifelse(wdf$up1[i-1] || wdf$up2[i-1] || wdf$dn1[i-1] || wdf$dn2[i-1], wdf$Close[i-1], wdf$pos_price[i-1]))

wdf$pos_close[i] <- (((wdf$position[i] > 0 & wdf$bar[i] == 1 ) || (wdf$position[i] < 0 & wdf$bar[i] == -1)) & wdf$body[i] > wdf$abody[i] / 2 )

wdf$balance[i] <- ifelse( wdf$position[i] > 0 , ifelse(i==1, 10000 + wdf$body[i] * wdf$bar[i], wdf$balance[i-1] + wdf$body[i] * wdf$bar[i]), wdf$balance[i-1] )

wdf$balance[i] <- ifelse( is.na(wdf$balance[i]), 10000, wdf$balance[i])

}

Итак, относительно небольшим кодом мы вычислили результаты стратегии для часового таймфрейма BTC/USD.

Результат выводим в виде графика

plot(wdf$Timestamp, wdf$Close, type="l", xlab="Date", ylab="Price")

lines(wdf$Timestamp,wdf$balance,col="green")

В итоге мы проверили, что за 3 месяца стратегия принесла более 20 процентов.

Хорошо это или плохо, решать вам.

По всем вопросам обращайтесь: Alexey @aav_1980

Только авторизованные пользователи могут оставлять новые комментарии

Популярные блоги по теме