Saturday, October 5, 2024

Optimized Values

 RVNL




grse optimization to find BRs

 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:

  1. Optimization setup: We can use an optimization library such as DEoptim (Differential Evolution), or a simple grid search to optimize the thresholds.
  2. Objective: Minimize the standard deviation (volatility) of the equity curve while maximizing the total returns. This will smooth the equity curve.
  3. 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. 
  4. 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.
  5. Optimized Conditions:

    • After optimization, the best values for the breakout threshold, breakdown threshold, and upper percentage are used to run the strategy.
  6. 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.
  7. 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)


Friday, October 4, 2024

Exploring Models on GDP Growth

We can use the Solow Growth Model as a simple example, which assumes that output (GDP) is determined by the Cobb-Douglas production function:

Y(t)=A(t)K(t)αL(t)1αY(t) = A(t) \cdot K(t)^{\alpha} \cdot L(t)^{1-\alpha}

Where:

  • Y(t)Y(t) is the output at time tt,
  • A(t)A(t) is the level of technology (or productivity),
  • K(t) is the capital stock,
  • L(t)L(t) is the labor input,
  • α\alpha is the capital's share of income.

Breakdown of Key Variables:

  • Savings rate (s): Determines how much of the economy’s output is invested back into capital. Higher savings rates lead to higher levels of capital and output in the steady state.
  • Depreciation rate (δ): Capital wears out over time, and the economy must invest enough to replace depreciated capital.
  • Technological progress (γ): The key driver of long-term economic growth. Technological improvements increase productivity, allowing the economy to produce more output with the same inputs.
  • Labor growth (η): Population and labor force growth influence how fast the economy needs to accumulate capital to keep up with a growing workforce.

Steps to Simulate Economic Growth:

  1. Define Initial Parameters: Set initial values for capital, labor, and productivity.
  2. Simulate Growth Over Time: Use equations to update capital, labor, and productivity at each time step.
  3. Plot the Results: Visualize the simulated economic growth using ggplot2.
CODE:

# Load necessary libraries
library(ggplot2)

# Set initial parameters for the simulation
alpha <- 0.33  # Capital share of income
beta <- 0.02   # Productivity growth rate
savings_rate <- 0.2  # Savings rate
depreciation <- 0.05 # Depreciation rate
labor_growth <- 0.01 # Labor growth rate
time_periods <- 100  # Simulation time horizon

# Initialize variables
A <- 1           # Initial productivity level
K <- 1           # Initial capital stock
L <- 1           # Initial labor input
gdp <- numeric(time_periods)  # Vector to store GDP values over time

# Simulate growth over time using Solow model
for (t in 1:time_periods) {
  # Calculate GDP using Cobb-Douglas production function
  Y <- A * K^alpha * L^(1 - alpha)
  gdp[t] <- Y
  
  # Update capital, productivity, and labor for the next period
  K <- (1 - depreciation) * K + savings_rate * Y  # Capital accumulation
  A <- A * (1 + beta)  # Productivity growth
  L <- L * (1 + labor_growth)  # Labor growth
}

# Create a data frame for plotting
data <- data.frame(
  Time = 1:time_periods,
  GDP = gdp
)

# Plot the GDP growth over time using ggplot2
ggplot(data, aes(x = Time, y = GDP)) +
  geom_line(color = "blue", size = 1) +
  labs(title = "Simulated Economic Growth (Solow Model)",
       x = "Time Period",
       y = "GDP") +
  theme_minimal()


We can create shiny interactive dashboards!


# Load necessary libraries
library(shiny)
library(ggplot2)

# Define UI for the Solow Growth Model Dashboard
ui <- fluidPage(
  
  # App title
  titlePanel("Solow Growth Model Simulation"),
  
  # Sidebar layout with input controls
  sidebarLayout(
    
    # Sidebar panel for inputs
    sidebarPanel(
      
      # Slider input for savings rate
      sliderInput("savings_rate", 
                  "Savings Rate (s):", 
                  min = 0.05, 
                  max = 0.5, 
                  value = 0.2, 
                  step = 0.01),
      
      # Slider input for depreciation rate
      sliderInput("depreciation_rate", 
                  "Depreciation Rate (δ):", 
                  min = 0.01, 
                  max = 0.1, 
                  value = 0.05, 
                  step = 0.01),
      
      # Slider input for labor growth rate
      sliderInput("labor_growth", 
                  "Labor Growth Rate (n):", 
                  min = 0.005, 
                  max = 0.05, 
                  value = 0.01, 
                  step = 0.001),
      
      # Slider input for technological growth rate
      sliderInput("tech_growth", 
                  "Technological Growth Rate (g):", 
                  min = 0.01, 
                  max = 0.05, 
                  value = 0.02, 
                  step = 0.001)
      
    ),
    
    # Main panel for displaying the GDP plot
    mainPanel(
      plotOutput("gdpPlot")  # Output plot
    )
    
  )
)

# Define server logic for the Solow Growth Model
server <- function(input, output) {
  
  # Reactive expression to simulate GDP over time based on user inputs
  solowModel <- reactive({
    
    # Parameters from user inputs
    alpha <- 0.33  # Capital share of income
    s <- input$savings_rate  # User-defined savings rate
    delta <- input$depreciation_rate  # User-defined depreciation rate
    n <- input$labor_growth  # User-defined labor growth rate
    g <- input$tech_growth  # User-defined technological growth rate
    time_periods <- 100  # Time horizon
    
    # Initialize variables
    A <- 1  # Initial productivity
    L <- 1  # Initial labor
    K <- 1  # Initial capital
    gdp <- numeric(time_periods)  # Vector to store GDP values
    
    # Simulate the Solow model over time
    for (t in 1:time_periods) {
      Y <- A * K^alpha * L^(1 - alpha)  # Cobb-Douglas production function
      gdp[t] <- Y  # Store GDP
      
      # Capital accumulation and updates for next period
      K <- (1 - delta) * K + s * Y
      A <- A * (1 + g)  # Productivity grows
      L <- L * (1 + n)  # Labor grows
    }
    
    # Return the GDP data
    data.frame(Time = 1:time_periods, GDP = gdp)
  })
  
  # Render the GDP plot
  output$gdpPlot <- renderPlot({
    data <- solowModel()
    
    # Plot using ggplot2
    ggplot(data, aes(x = Time, y = GDP)) +
      geom_line(color = "blue", size = 1) +
      labs(title = "Simulated Economic Growth (Solow Growth Model)",
           x = "Time Period",
           y = "GDP") +
      theme_minimal()
  })
}

# Run the Shiny app
shinyApp(ui = ui, server = server)

Types of Shocks:

  1. Productivity Shock: A random shock that affects the level of productivity (e.g., technological innovation or a recession).
  2. Capital Shock: A random shock to the capital accumulation process (e.g., natural disasters that destroy capital).
  3. Labor Shock: A random shock to labor growth (e.g., demographic changes or pandemic).

We'll implement a random productivity shock in this example. Each period, the productivity A(t)A(t) will be multiplied by a random factor drawn from a normal distribution to simulate positive or negative shocks.

Example Output:

  • With a low shock volatility, you will see a smooth GDP curve as the economy grows steadily.
  • As you increase the shock volatility, you will notice more fluctuations and random jumps in GDP growth, simulating unpredictable events.





Wednesday, October 2, 2024

The revolutionary use of R in data analysis to explore the stock market

R is a free, open-source programming language and statistical computing environment that's used for data analysis, visualization, and machine learning. It's a domain-specific language (DSL) designed for statistical computing and analysis. 

This is what shows up when you search "what is R" on Google. I must say, it is truly out of the world, that you can run codes and backtest your hypotheses. Being from Mechanical Engineering background, I find coding to be a meticulous subject for me to master, respecc to all those CSE bros and sis' who do it. But with the advent of CHATGPT, and R, it is way way easier to just give your propositions, run the GPT and get codes to substitute in R studio to create visualizations. 

For now, I am thinking about running backtests with basic momentum bursts in stocks, and see how they perform with an equity curve visualization. 

Condition: buy if it is up 3% during the day, with initial stoploss at day range half, and sell only between 8-20% gain, within 3 to 5 days.


Code Used: 

# Required Libraries
if (!require(quantmod)) install.packages("quantmod")
if (!require(dplyr)) install.packages("dplyr")
if (!require(ggplot2)) install.packages("ggplot2")

library(quantmod)
library(dplyr)
library(ggplot2)

# Download stock data for HAL.NS from Yahoo Finance
getSymbols("HAL.NS", from = "2020-01-01", to = Sys.Date(), src = "yahoo")
stock_data <- HAL.NS

# Convert to data frame for easier manipulation
stock_df <- data.frame(Date = index(stock_data), coredata(stock_data))

# Calculate daily percentage change, day's range, and stop loss price
stock_df <- stock_df %>%
  mutate(
    Day_Pct_Change = 100 * (HAL.NS.Close - lag(HAL.NS.Close)) / lag(HAL.NS.Close),
    Day_Range = HAL.NS.High - HAL.NS.Low,
    Stop_Loss_Price = HAL.NS.Close - (Day_Range / 2),
    Daily_Return = (HAL.NS.Close / lag(HAL.NS.Close)) - 1
  )

# Initialize signals and tracking columns
stock_df <- stock_df %>%
  mutate(
    Buy_Signal = ifelse(Day_Pct_Change > 3, 1, 0),
    Sell_Signal = 0,
    Entry_Price = NA,
    Exit_Price = NA,
    In_Trade = FALSE,
    Trade_Start_Index = NA,
    Strategy_Return = NA,
    Cumulative_Return = 1  # Initialize for cumulative returns calculation
  )

# Loop through the data and apply the momentum burst strategy
for (i in 2:nrow(stock_df)) {
  if (!stock_df$In_Trade[i-1]) {
    # Not in a trade, check for buy signal
    if (stock_df$Buy_Signal[i] == 1) {
      # Enter trade
      stock_df$Entry_Price[i] <- stock_df$HAL.NS.Close[i]
      stock_df$Stop_Loss_Price[i] <- stock_df$Entry_Price[i] - (stock_df$Day_Range[i] / 2)
      stock_df$In_Trade[i] <- TRUE
      stock_df$Trade_Start_Index[i] <- i
    }
  } else {
    # In a trade, carry forward trade details
    stock_df$Entry_Price[i] <- stock_df$Entry_Price[i-1]
    stock_df$Stop_Loss_Price[i] <- stock_df$Stop_Loss_Price[i-1]
    stock_df$Trade_Start_Index[i] <- stock_df$Trade_Start_Index[i-1]
    stock_df$In_Trade[i] <- TRUE
    
    # Calculate profit percentage and trade duration
    profit_pct <- 100 * (stock_df$HAL.NS.Close[i] - stock_df$Entry_Price[i]) / stock_df$Entry_Price[i]
    trade_duration <- i - stock_df$Trade_Start_Index[i] + 1
    
    # Exit conditions
    if (stock_df$HAL.NS.Close[i] <= stock_df$Stop_Loss_Price[i]) {
      # Stop loss hit
      stock_df$Exit_Price[i] <- stock_df$HAL.NS.Close[i]
      stock_df$Sell_Signal[i] <- 1
      stock_df$In_Trade[i] <- FALSE
      stock_df$Strategy_Return[i] <- (stock_df$Exit_Price[i] / stock_df$Entry_Price[i-1]) - 1
    } else if (trade_duration >= 3) {
      if (profit_pct >= 8 && profit_pct <= 20) {
        # Profit target met between 3-5 days
        stock_df$Exit_Price[i] <- stock_df$HAL.NS.Close[i]
        stock_df$Sell_Signal[i] <- 1
        stock_df$In_Trade[i] <- FALSE
        stock_df$Strategy_Return[i] <- (stock_df$Exit_Price[i] / stock_df$Entry_Price[i-1]) - 1
      } else if (trade_duration >= 5) {
        # Maximum trade duration reached
        stock_df$Exit_Price[i] <- stock_df$HAL.NS.Close[i]
        stock_df$Sell_Signal[i] <- 1
        stock_df$In_Trade[i] <- FALSE
        stock_df$Strategy_Return[i] <- (stock_df$Exit_Price[i] / stock_df$Entry_Price[i-1]) - 1
      }
    }
  }
  
  # Ensure In_Trade is logical
  if (is.na(stock_df$In_Trade[i])) {
    stock_df$In_Trade[i] <- FALSE
  }
  
  # Cumulative returns calculation
  if (!is.na(stock_df$Strategy_Return[i])) {
    stock_df$Cumulative_Return[i] <- stock_df$Cumulative_Return[i-1] * (1 + stock_df$Strategy_Return[i])
  } else {
    stock_df$Cumulative_Return[i] <- stock_df$Cumulative_Return[i-1]
  }
}

# Extract trades for analysis
trades <- stock_df %>%
  filter(Sell_Signal == 1) %>%
  mutate(
    Entry_Date = stock_df$Date[Trade_Start_Index],
    Profit = Exit_Price - Entry_Price,
    Profit_Pct = 100 * Profit / Entry_Price
  ) %>%
  select(Entry_Date, Date, Entry_Price, Exit_Price, Profit, Profit_Pct)

# Summary Statistics
total_trades <- nrow(trades)
winning_trades <- nrow(trades %>% filter(Profit_Pct > 0))
losing_trades <- nrow(trades %>% filter(Profit_Pct <= 0))
average_profit <- mean(trades$Profit_Pct)
cumulative_return <- tail(stock_df$Cumulative_Return, 1)
win_loss_ratio <- winning_trades / losing_trades

# Display summary statistics
cat("Total Trades:", total_trades, "\n")
cat("Winning Trades:", winning_trades, "\n")
cat("Losing Trades:", losing_trades, "\n")
cat("Average Profit per Trade:", average_profit, "%\n")
cat("Cumulative Return of Strategy:", cumulative_return - 1, "\n")
cat("Win/Loss Ratio:", win_loss_ratio, "\n")

# Plot cumulative returns using ggplot2
ggplot(stock_df, aes(x = Date, y = Cumulative_Return)) +
  geom_line(color = "blue", size = 1) +
  labs(
    title = "Cumulative Return of Momentum Burst Strategy on HAL.NS",
    x = "Date",
    y = "Cumulative Return",
    caption = "Momentum Burst Strategy"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))


A few are given below for HAL & RVNL:







Optimized Values

 RVNL