To optimize the buy and sell conditions to create a smoother equity curve, we can employ several techniques. One possible approach is to tune the breakout and breakdown conditions using optimization methods such as grid search, genetic algorithms, or optimization libraries. We'll explore how to adjust the conditions for a better risk-adjusted return, such as:
- Varying the breakout threshold (currently set at 3%).
- Modifying the closing percentage range in the upper 30%.
- Adjusting the breakdown threshold (currently set at -3%).
Approach:
- Optimization setup: We can use an optimization library such as
DEoptim
(Differential Evolution), or a simple grid search to optimize the thresholds. - Objective: Minimize the standard deviation (volatility) of the equity curve while maximizing the total returns. This will smooth the equity curve.
- Optimization of buy/sell conditions: Tune the breakout threshold (currently 3%) and breakdown threshold (currently -3%) to achieve a better trade-off between return and risk.
Optimization using
DEoptim
:- We define a function
trading_strategy()
that calculates the return and volatility of the strategy based on input parameters. - The parameters being optimized are:
breakout_threshold
: The percentage change threshold to buy (currently set at 3%).breakdown_threshold
: The percentage change threshold to sell (currently set at -3%).upper_percentage
: The percentage of the day range within which the stock must close to trigger a breakout.
- The objective of the optimization is to minimize volatility and maximize returns, which leads to a smoother equity curve.
- We define a function
Optimized Conditions:
- After optimization, the best values for the breakout threshold, breakdown threshold, and upper percentage are used to run the strategy.
Plot and Output:
- The plot displays the optimized buy and sell signals on the price chart and the smoother equity curve based on the optimized conditions.
Customization:
You can adjust the upper/lower bounds in lower_bounds
and upper_bounds
to explore different ranges of thresholds. The DEoptim
algorithm can also be replaced with grid search or another optimization method if desired.
# Required Libraries
install.packages("DEoptim")
library(quantmod)
library(DEoptim) # For optimization
library(dplyr)
library(ggplot2)
# Step 1: Download GRSE.NS data
symbol <- "GRSE.NS"
getSymbols(symbol, from = "2010-01-01", to = Sys.Date())
grse_data <- data.frame(date = index(GRSE.NS), coredata(GRSE.NS))
# Step 2: Define the function for the trading strategy
trading_strategy <- function(params) {
breakout_threshold <- params[1] # Buy on breakout threshold
breakdown_threshold <- params[2] # Sell on breakdown threshold
upper_percentage <- params[3] # Upper day range percentage
# Calculate breakout and breakdown conditions based on parameters
grse_data <- grse_data %>%
mutate(
perc_change = (GRSE.NS.Close - lag(GRSE.NS.Close)) / lag(GRSE.NS.Close) * 100,
day_range = GRSE.NS.High - GRSE.NS.Low,
upper_condition = GRSE.NS.High - GRSE.NS.Close <= upper_percentage * day_range,
breakout = ifelse(perc_change >= breakout_threshold & upper_condition, TRUE, FALSE),
breakdown = ifelse(perc_change <= breakdown_threshold, TRUE, FALSE)
)
# Step 3: Trading strategy: Buy on breakout, sell on breakdown
trades <- data.frame(buy_date = as.Date(character()), buy_price = numeric(),
sell_date = as.Date(character()), sell_price = numeric(),
return = numeric(), stringsAsFactors = FALSE)
position_open <- FALSE
capital <- 100000 # Initial capital
equity_curve <- rep(capital, nrow(grse_data))
for (i in 2:nrow(grse_data)) {
# Skip if breakout or breakdown is NA
if (is.na(grse_data$breakout[i]) | is.na(grse_data$breakdown[i])) next
# Buy on breakout
if (grse_data$breakout[i] && !position_open) {
buy_price <- grse_data$GRSE.NS.Close[i]
position_open <- TRUE
}
# Sell on breakdown
if (position_open && grse_data$breakdown[i]) {
sell_price <- grse_data$GRSE.NS.Close[i]
return_trade <- (sell_price - buy_price) / buy_price
capital <- capital * (1 + return_trade)
position_open <- FALSE
}
# Update equity curve
equity_curve[i] <- capital
}
# Return objective to minimize: negative total return and volatility
total_return <- (capital - 100000) / 100000
volatility <- sd(diff(equity_curve[equity_curve > 0])) / mean(equity_curve)
# Minimize the negative of total return and volatility (for a smoother curve)
return(-total_return + volatility)
}
# Step 4: Use DEoptim for optimization
lower_bounds <- c(1, -5, 0.1) # Lower bounds for breakout, breakdown, and upper_percentage
upper_bounds <- c(5, -1, 0.5) # Upper bounds for breakout, breakdown, and upper_percentage
# Run optimization
optim_results <- DEoptim(trading_strategy, lower = lower_bounds, upper = upper_bounds,
control = list(itermax = 50))
# Extract optimized parameters
best_params <- optim_results$optim$bestmem
breakout_threshold <- best_params[1]
breakdown_threshold <- best_params[2]
upper_percentage <- best_params[3]
# Step 5: Run the optimized trading strategy and plot results
grse_data <- grse_data %>%
mutate(
perc_change = (GRSE.NS.Close - lag(GRSE.NS.Close)) / lag(GRSE.NS.Close) * 100,
day_range = GRSE.NS.High - GRSE.NS.Low,
upper_condition = GRSE.NS.High - GRSE.NS.Close <= upper_percentage * day_range,
breakout = ifelse(perc_change >= breakout_threshold & upper_condition, TRUE, FALSE),
breakdown = ifelse(perc_change <= breakdown_threshold, TRUE, FALSE)
)
# Trading strategy: Buy on breakout, sell on breakdown
trades <- data.frame(buy_date = as.Date(character()), buy_price = numeric(),
sell_date = as.Date(character()), sell_price = numeric(),
return = numeric(), stringsAsFactors = FALSE)
position_open <- FALSE
capital <- 100000 # Initial capital
equity_curve <- data.frame(date = grse_data$date, equity = capital)
for (i in 2:nrow(grse_data)) {
# Skip if breakout or breakdown is NA
if (is.na(grse_data$breakout[i]) | is.na(grse_data$breakdown[i])) next
# Buy on breakout
if (grse_data$breakout[i] && !position_open) {
buy_price <- grse_data$GRSE.NS.Close[i]
buy_date <- grse_data$date[i]
position_open <- TRUE
}
# Sell on breakdown
if (position_open && grse_data$breakdown[i]) {
sell_price <- grse_data$GRSE.NS.Close[i]
sell_date <- grse_data$date[i]
return_trade <- (sell_price - buy_price) / buy_price
capital <- capital * (1 + return_trade)
trades <- rbind(trades, data.frame(buy_date = buy_date, buy_price = buy_price,
sell_date = sell_date, sell_price = sell_price,
return = return_trade))
position_open <- FALSE
}
# Update equity curve
equity_curve$equity[i] <- capital
}
# Step 6: Plot the trades and equity curve
# Plot trades on price chart
ggplot(grse_data, aes(x = date, y = GRSE.NS.Close)) +
geom_line() +
geom_point(data = trades, aes(x = buy_date, y = buy_price), color = "green", size = 3, shape = 17) +
geom_point(data = trades, aes(x = sell_date, y = sell_price), color = "red", size = 3, shape = 18) +
ggtitle("GRSE.NS Price with Optimized Breakout Buy (Green) and Breakdown Sell (Red)") +
xlab("Date") + ylab("Price") +
theme_minimal()
# Plot equity curve
ggplot(equity_curve, aes(x = date, y = equity)) +
geom_line(color = "blue") +
ggtitle("Equity Curve (Optimized Compounded)") +
xlab("Date") + ylab("Equity") +
theme_minimal()
# Display trades table
print(trades)
No comments:
Post a Comment