braverock / quantstrat

289 stars 114 forks source link

using bloomberg OHLC bars #123

Closed thestockman27 closed 4 years ago

thestockman27 commented 4 years ago

Hi there,

I am attempting to use data from bloomberg to run a backtesting strategy. Our firm uses $HYG as a hedging instrument and I am running some backtests on it to get a better understanding of how it behaves. I have also been thinking about running tick level OHLC data through here for fun. Not sure if that is possible though.

I am wondering if anyone has experience using data from this source within the quantstrat framework. I have noticed that the first issue is with converting the data to xts format, but having solved for that in the setup portion, there appears to be some more formatting issues as applyStrategy() returns an empty object.

Any and all assistance would be appreciated. Thanks for your time and efforts on this package!

jaymon0703 commented 4 years ago

Hi @thestockman27. You may need to clarify what you mean by tick level OHLC data. Is that just OHLC at higher frequency intervals than daily, for example? It is certainly possible to use higher frequency data, and even using BBO data (indeed the author of this package's preference when making execution assumptions) as opposed to simply OHLC bars.

As for the issue to which you allude, we would require at least a reproducible example in order to comment/assist.

Thanks.

thestockman27 commented 4 years ago

adding xlsx file

HYG.xlsx

thestockman27 commented 4 years ago

adding my code:, an adaptation of the datacamp course:

library(quantstrat)
library(timeDate)
library(TTR)
library(quantmod)
library(Rblpapi)
Rblpapi::blpConnect()

Get SPY from yahoo
hyg <-getSymbols("HYG", 
           from = "2015-01-01",
           # to = "2016-06-30",
           src = "yahoo",
           adjust = TRUE)
HYG_bb <- getBars("HYG US EQUITY", 
        eventType = "TRADE",
        barInterval = 60*7 +30,
        startTime =as.POSIXct(Sys.Date() - 2000),#as.Date("2015-01-01", format = "%m/%d/%Y"),
        #endTime = =as.POSIXct(Sys.Date()),
        options = NULL, 
        verbose = FALSE,
        returnAs = getOption("blpType","matrix"),
        tz = Sys.getenv("TZ", unset = "EST"),
        con = defaultConnection())
rownames(HYG_bb)<- HYG_bb[,1]
HYG_bb_xts <- as.xts(HYG_bb[,-1])
HYG <- HYG_bb_xts
# Plot the closing price of SPY
plot(Cl(HYG))

# Add a 200-day SMA using lines()
lines(SMA(Cl(HYG), n = 50), col = "red")
lines(SMA(Cl(HYG), n = 20), col = "blue")
lines(SMA(Cl(HYG), n = 5), col = "green")

#### Set-up ####
# Create initdate, from, and to strings
initdate <- "1999-01-01"
from <- as.character(gsub(" 09:30:00","",HYG_bb[1,1]))
to <- as.character(gsub(" 08:30:00","",HYG_bb[nrow(HYG_bb),1]))

# Set the timezone to EST
Sys.setenv(TZ = "EST")
# Set the currency to USD 
currency("USD")

stock("HYG", currency = "USD")

# Define your trade size and initial equity
tradesize <- 100000
initeq <- 100000

# Define the names of your strategy, portfolio and account
strategy.st <- "HYGstrat"
portfolio.st <- "HYGstrat"
account.st <- "HYGstrat"

# Remove the existing strategy if it exists
rm.strat(strategy.st)
rm.strat("HYGstrat")
# Initialize the portfolio
initPortf(portfolio.st, symbols = "HYG", initDate = initdate, currency = "USD")

# Initialize the account
initAcct(account.st, portfolios = portfolio.st, initDate = initdate, currency = "USD", initEq = initeq)

# Initialize the orders
initOrders(portfolio.st, initDate = initdate)

# Store the strategy
strategy(strategy.st, store = TRUE)

#### Indicators ####
# Add a 20-day SMA indicator to strategy.st
add.indicator(strategy = strategy.st, 

              # Add the SMA function
              name = "SMA", 

              # Create a lookback period
              arguments = list(x = quote(Cl(mktdata)), n = 20), 

              # Label your indicator SMA200
              label = "SMA20")
# Add a 5-day SMA indicator to strategy.st
add.indicator(strategy = strategy.st, 

              # Add the SMA function
              name = "SMA", 

              # Create a lookback period
              arguments = list(x = quote(Cl(mktdata)), n = 5), 

              # Label your indicator SMA50
              label = "SMA5")
# Add an RSI 3 indicator to strategy.st
add.indicator(strategy = strategy.st, 

              # Add the RSI 3 function
              name = "RSI", 

              # Create a lookback period
              arguments = list(price = quote(Cl(mktdata))), 

              # Label your indicator RSI_3
              label = "RSI")
# # Write the calc_RSI_avg function
calc_RSI_avg <- function(price, n1, n2) {

  # RSI 1 takes an input of the price and n1
  RSI_1 <- RSI(price = price, n = n1)

  # RSI 2 takes an input of the price and n2
  RSI_2 <- RSI(price = price, n = n2)

  # RSI_avg is the average of RSI_1 and RSI_2
  RSI_avg <- (RSI_1 + RSI_2)/2

  # Your output of RSI_avg needs a column name of RSI_avg
  colnames(RSI_avg) <- "RSI_avg"
  return(RSI_avg)
}

# Add this function as RSI_3_4 to your strategy with n1 = 3 and n2 = 4
add.indicator(strategy.st, name = "calc_RSI_avg", arguments = list(price = quote(Cl(mktdata)), n1 = 3, n2 = 4), label = "RSI_3_4")

test <- applyIndicators(strategy = strategy.st, 
                        mktdata = OHLC(HYG), 
                        price = Cl(HYG)
)
# Subset your data between Sep. 1 and Sep. 5 of 2018
#test_subset <- test["2018-09-01/2018-10-05"]

# Declare the DVO function
DVO <- function(HLC, navg = 2, percentlookback = 126) {

  # Compute the ratio between closing prices to the average of high and low
  ratio <- Cl(HLC)/((Hi(HLC) + Lo(HLC))/2)

  # Smooth out the ratio outputs using a moving average
  avgratio <- SMA(ratio, n = navg)

  # Convert ratio into a 0-100 value using runPercentRank()
  out <- runPercentRank(avgratio, n = percentlookback, exact.multiplier = 1) * 100
  colnames(out) <- "DVO"
  return(out)
}
# Add the DVO indicator to your strategy
add.indicator(strategy = strategy.st, name = "DVO", 
              arguments = list(HLC = quote(HLC(mktdata)), navg = 2, percentlookback = 126),
              label = "DVO_2_126")

# Use applyIndicators to test out your indicators
test <- applyIndicators(strategy = strategy.st, mktdata = OHLC(HYG), price = Cl(HYG))

#### Signals ####
# Add a sigComparison which specifies that SMA5 must be greater than SMA20, call it longfilter
add.signal(strategy.st, name = "sigComparison", 

           # We are interested in the relationship between the SMA5 and the SMA20
           arguments = list(columns = c("SMA5", "SMA20"), 

                            # Particularly, we are interested when the SMA5 is greater than the SMA20
                            relationship = "gt"),

           # Label this signal longfilter
           label = "longfilter")

# Add a sigCrossover which specifies that the SMA5 is less than the SMA20 and label it filterexit
add.signal(strategy.st, name = "sigCrossover",

           # We're interested in the relationship between the SMA5 and the SMA20
           arguments = list(columns = c("SMA5", "SMA20"),

                            # The relationship is that the SMA5 crosses under the SMA20
                            relationship = "lt"),

           # Label it filterexit
           label = "filterexit")

add.signal(strategy.st, name = "sigThreshold", 
           arguments = list(column = "DVO_2_126", 
                            threshold = 20, 
                            relationship = "lt",
                            cross = FALSE),
           label = "longthreshold")

# Add a sigThreshold signal to your strategy that specifies that DVO_2_126 must cross above 80 and label it thresholdexit
add.signal(strategy.st, name = "sigThreshold",
           arguments = list(column = "DVO_2_126", 
                            threshold = 80, 
                            relationship = "gt", 
                            cross = TRUE), 
           label = "thresholdexit")

# Add a sigFormula signal to your code specifying that both longfilter and longthreshold must be TRUE, label it longentry
add.signal(strategy.st, name = "sigFormula",
           arguments = list(formula = "longfilter & longthreshold", 
                            cross = TRUE),
           label = "longentry")
# Create your dataset: test
test_init <- applyIndicators(strategy.st, mktdata = OHLC(HYG), price = Cl(HYG))
test <- applySignals(strategy = strategy.st, mktdata = test_init)

#### Rules ####
add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments = list(sigcol = "filterexit", 
                          sigval = TRUE, 
                          orderqty = "all", 
                          ordertype = "market", 
                          orderside = "long", 
                          replace = FALSE, 
                          prefer = "Open"), 
         type = "exit")
# Fill in the replace argument in add.rule()
add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments = list(sigcol = "thresholdexit", 
                          sigval = TRUE, 
                          orderqty = "all", 
                          ordertype = "market", 
                          orderside = "long", 
                          replace = FALSE, 
                          prefer = "Open"), 
         type = "exit")

# Create an entry rule of 1 share when all conditions line up to enter into a position
add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments=list(sigcol = "longentry", 
                        sigval = TRUE, 
                        orderqty = 1,
                        ordertype = "market",
                        orderside = "long",
                        replace = FALSE, 
                        prefer = "Open"),

         type = "enter")

#### Apply the Strategy ####
# Use applyStrategy() to apply your strategy. Save this to out
out <- applyStrategy(strategy = strategy.st, portfolios = portfolio.st)

# Update your portfolio (portfolio.st)
updatePortf(portfolio.st)
daterange <- time(getPortfolio(portfolio.st)$summary)[-1]

# Update your account (account.st)
updateAcct(account.st, daterange)
updateEndEq(account.st)

# Get the tradeStats for your portfolio
tstats <- tradeStats(Portfolios = portfolio.st)

# Print the profit factor
print(tstats$Profit.Factor)

# Use chart.Posn to view your system's performance on SPY
chart.Posn(Portfolio = portfolio.st, Symbol = "HYG")
# Compute the SMA50
sma50 <- SMA(x = Cl(HYG), n = 50)

# Compute the SMA200
sma200 <- SMA(x = Cl(HYG), n = 200)

# Compute the DVO_2_126 with an navg of 2 and a percentlookback of 126
dvo <- DVO(HLC = HLC(HYG), percentlookback = 126)

# Recreate the chart.Posn of the strategy from the previous exercise
chart.Posn(Portfolio = portfolio.st, Symbol = "HYG")

# Overlay the SMA50 on your plot as a blue line
add_TA(sma50, on = 1, col = "blue")

# Overlay the SMA200 on your plot as a red line
add_TA(x = sma200, on = 1, col = "red")

# Add the DVO_2_126 to the plot in a new window
add_TA(dvo)
thestockman27 commented 4 years ago

Yes, I am referring to higher frequency Open/High/Low/Close data.

The code above runs until the applyStrategy() command. Gotta be the data formatting right?

jaymon0703 commented 4 years ago

I dont have a Bloomberg terminal so that part of your code is not generally reproducible. Is the length of the dataset you are using merely what you have included in the attachment? If you get an output for applyIndicators and applySignals, then you should get a result for applyRules as well. Do you get results for those funciton calls?

thestockman27 commented 4 years ago

Apologies, saved the wrong dataset. This is the output from the getBars function. Should run smoothly from that rownames() command. Yes, it is a small dataset, only 134 observations, for the sake of testing whether I could get the format converted to something legible by the quantstrat framework. HYG_bb.xlsx

Both applyIndicators and applySignals generate proper outputs. ApplyRules (called through applyStrategy) does not.

jaymon0703 commented 4 years ago

The signal conditions for initiating a long entry are never fulfilled which means sigval never equals TRUE for the longentry rule to fire. You can see this in the mktdata object.

thestockman27 commented 4 years ago

yikes - sorry to have wasted your time!

jaymon0703 commented 4 years ago

No worries, thanks for closing the issue.