Introduction

This document optimizes trend-following and mean-reversion strategies for BIST 100 using blotter, tracking portfolio performance, and visualizing equity curves.

Loading Libraries and Initialize the Blotter

# Clear existing environments
rm(list = ls(all.names = TRUE))
gc()
##           used (Mb) gc trigger (Mb) limit (Mb) max used (Mb)
## Ncells  616582 33.0    1411540 75.4         NA   700245 37.4
## Vcells 1165743  8.9    8388608 64.0      16384  1963281 15.0
# Load required libraries
libraries <- c("quantstrat", "PerformanceAnalytics", "TTR", 
               "blotter", "FinancialInstrument", "quantmod", 
               "ggplot2", "reshape2")
invisible(lapply(libraries, library, character.only = TRUE))
## Loading required package: quantmod
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## Loading required package: blotter
## Loading required package: FinancialInstrument
## Loading required package: PerformanceAnalytics
## 
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
## 
##     legend
## Loading required package: foreach
# Set global options
options(verbose = FALSE)
Sys.setenv(TZ = "UTC")

# Initialize blotter account and portfolio
initDate <- "2000-01-01"
currency("USD")
## [1] "USD"
stock("XU100.IS", currency = "USD", multiplier = 1)
## [1] "XU100.IS"
initEq <- 100000

# Portfolio and account setup
strategy_name <- "BIST_Strategy"
account_name <- "BIST_Account"
portfolio_name <- "BIST_Portfolio"

if (!exists('.blotter')) .blotter <- new.env()
if (!exists('.strategy')) .strategy <- new.env()

initPortf(portfolio_name, symbols = "XU100.IS", initDate = initDate)
## [1] "BIST_Portfolio"
initAcct(account_name, portfolios = portfolio_name, initDate = initDate, initEq = initEq)
## [1] "BIST_Account"
initOrders(portfolio_name, initDate = initDate)

Procces Bist 100 Data and Omit the missing Values

# Retrieve BIST 100 data
XU100.IS <- getSymbols("XU100.IS", src = "yahoo", from = "2010-01-01", to = "2020-01-01", auto.assign = FALSE)
## Warning: XU100.IS contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
XU100.IS <- na.omit(XU100.IS)
prices <- Cl(XU100.IS)

# Diagnostics
cat("Total observations:", nrow(prices), "\n")
## Total observations: 2511
cat("Date range:", as.character(first(index(prices))), "to", as.character(last(index(prices))), "\n")
## Date range: 2010-01-04 to 2019-12-31

Strategy Optimization

# Function to place blotter trades
place_trade <- function(portfolio, symbol, trade_type, qty, price, timestamp) {
  addTxn(Portfolio = portfolio, Symbol = symbol, TxnDate = timestamp, TxnPrice = price, TxnQty = qty, TxnFees = 0, verbose = TRUE)
}

# Strategy Optimization Function
optimize_strategy <- function(prices, strategy_type = "trend_following", n_range = 1:8, m_range = 1:10) {
  returns <- ROC(prices, type = "discrete")  # Calculate returns
  returns <- na.omit(returns)                # Omit NA values from returns

  results <- data.frame(n = integer(), m = integer(), TotalReturn = numeric(), SharpeRatio = numeric(), MaxDrawdown = numeric())

  for (n in n_range) {
    for (m in m_range) {
      tryCatch({
        # Create trading signals
        if (strategy_type == "trend_following") {
          buy_signal <- runSum(returns > 0, n) == n
          sell_signal <- runSum(returns < 0, m) == m
        } else {
          buy_signal <- runSum(returns < 0, n) == n
          sell_signal <- runSum(returns > 0, m) == m
        }

        # Calculate strategy performance
        strategy_returns <- ifelse(buy_signal, returns, 0)
        total_return <- sum(strategy_returns, na.rm = TRUE)

        sharpe_ratio <- tryCatch({
          SharpeRatio.annualized(strategy_returns[strategy_returns != 0], Rf = 0)
        }, error = function(e) NA)

        max_drawdown <- tryCatch({
          maxDrawdown(strategy_returns)[[1]]
        }, error = function(e) 0)

        results <- rbind(results, data.frame(n = n, m = m, TotalReturn = total_return, SharpeRatio = sharpe_ratio, MaxDrawdown = max_drawdown))
      }, error = function(e) cat("Error:", conditionMessage(e), "\n"))
    }
  }
  return(results)
}

Running the Optimization

cat("Running Trend Following Optimization:\n")
## Running Trend Following Optimization:
trend_results <- optimize_strategy(prices, "trend_following")

cat("\nRunning Mean Reversion Optimization:\n")
## 
## Running Mean Reversion Optimization:
meanrev_results <- optimize_strategy(prices, "mean_reversion")
# Function to get best parameters based on TotalReturn
get_best_params <- function(results_df) {
  best_idx <- which.max(results_df$TotalReturn)
  return(results_df[best_idx, ])
}

# Get best parameters
best_trend <- get_best_params(trend_results)
best_meanrev <- get_best_params(meanrev_results)

# Create a data frame for the table
results_table <- data.frame(
  Strategy = c("Trend Following", "Mean Reversion"),
  n = c(best_trend$n, best_meanrev$n),
  m = c(best_trend$m, best_meanrev$m),
  TotalReturn = round(c(best_trend$TotalReturn, best_meanrev$TotalReturn), 4),
  SharpeRatio = round(c(best_trend$SharpeRatio, best_meanrev$SharpeRatio), 4),
  MaxDrawdown = round(c(best_trend$MaxDrawdown, best_meanrev$MaxDrawdown), 4)
)

# Print the table
print(results_table, row.names = FALSE)
##         Strategy n m TotalReturn SharpeRatio MaxDrawdown
##  Trend Following 1 1     13.5115     10.9634      0.0000
##   Mean Reversion 8 1     -0.1302     -1.1754      0.1275

Heatmap for best N-M pairs

# Heatmap for Trend Following
trend_matrix <- matrix(trend_results$TotalReturn, nrow=length(unique(trend_results$n)), 
                      byrow=TRUE)
trend_plot <- ggplot(trend_results, aes(x=n, y=m, fill=TotalReturn)) +
  geom_tile() +
  scale_fill_gradient(low="white", high="blue") +
  labs(title="Trend Following Returns Heatmap",
       x="n (Buy Signal)", y="m (Sell Signal)") +
  theme_minimal()

# Heatmap for Mean Reversion
meanrev_matrix <- matrix(meanrev_results$TotalReturn, nrow=length(unique(meanrev_results$n)), 
                        byrow=TRUE)
meanrev_plot <- ggplot(meanrev_results, aes(x=n, y=m, fill=TotalReturn)) +
  geom_tile() +
  scale_fill_gradient(low="white", high="red") +
  labs(title="Mean Reversion Returns Heatmap",
       x="n (Buy Signal)", y="m (Sell Signal)") +
  theme_minimal()

# Display plots
print(trend_plot)

print(meanrev_plot)

Save Envirenment

save.image()