Team 3 Members

  1. Gurram Manoj Reddy
  2. Kolloju Nagarjuna
  3. Phand Atharva Hemant
  4. Pitta Venkat

Summary

This tutorial presents a comprehensive approach to backtesting a trend-following trading strategy on S&P 500 energy sector stocks using daily OHLC (Open, High, Low, Close) data. Our strategy is based on a two-trend system that identifies and capitalizes on short-term and long-term market movements. The backtesting period extends from January 2022 through December 2023, with a starting investment capital of $100,000. This strategy permits both long and short positions, enabling flexibility in response to market trends.

Performance evaluation of the backtested strategy includes measures such as total return, Sharpe ratio, maximum drawdown, and win-loss ratio, providing a holistic view of the strategy’s effectiveness and risk-adjusted returns. Additionally, the tutorial details the optimization process for selecting the best parameters for the moving averages and other parameters ensuring the strategy is finely tuned for the specific characteristics of the energy sector.

Following the initial backtesting, the strategy is applied to another industrial sector, Information Technology to assess its versatility and performance in different market conditions. Furthermore, a retrospective analysis is conducted for the period January 2019 through December 2020 to compare the strategy’s performance during different market phases. This comparison reveals insights into the strategy’s adaptability and potential areas for adjustment in response to varying market environments.

The tutorial concludes with key takeaways, emphasizing the importance of trend analysis, risk management, and the adaptability of trading strategies across different sectors and time periods.

Learning Outcomes:

  1. Understanding of Financial Market Data Manipulation: Learners will gain hands-on experience in manipulating and analyzing financial market data, focusing on OHLC (Open, High, Low, Close) data and moving averages, which are crucial for trend analysis.

  2. Application of Technical Analysis in Trading: The script applies fundamental concepts of technical analysis, such as moving averages, to generate buy or sell signals. This provides practical insights into how traders can use historical price data to make informed decisions.

  3. Development of Trading Strategies: By following this script, learners will understand the steps involved in developing and testing a trading strategy. This includes setting initial capital, defining trading signals, managing positions, and implementing risk management rules.

  4. Backtesting and Optimization: The script demonstrates how to backtest a trading strategy against historical data to evaluate its performance. This is vital for understanding the strategy’s potential profitability and risk before applying it in live trading.

  5. Risk Management: Through the implementation of maximum trade value and maximum daily trades, learners will appreciate the importance of risk management in trading. This includes how to size positions and when to exit trades to minimize losses.

  6. Performance Evaluation: The script calculates key performance metrics such as total return, Sharpe ratio, and maximum drawdown. Learning how to evaluate these metrics is crucial for assessing the strategy’s effectiveness and comparing it to other strategies or benchmarks.

Steps:

This tutorial breaks down the process of creating and testing a trading strategy into five clear steps, making it easier to follow and implement.

1. Trading Strategy Definition: We start by clearly laying out our trading strategy. This means clearly stating what we want to achieve, the signals that will tell us when to buy or sell, and the rules for starting and ending trades.

2. Setting Parameters: Next, we detail our strategy’s goals, risk levels, and other important benchmarks like maximum value per trade and maximum trades per day.

3. Generating Indicators : We generate technical indicators, Fast Moving Average (FMA) and Slow Moving Average (SMA), enabling the identification of trend-based trading signals.

4. Generating Signals : We then create a system to find buy or sell signals from past market data. This involves analyzing historical trends that match our strategy’s criteria to identify the best times to trade.

5. Applying Strategy Rules: Here, we turn the theoretical aspects of our strategy into actual trading actions. This means translating when and how we’ll enter and exit trades into concrete steps, ensuring our trades stick to our original plan.

6. Managing the Portfolio: This step focuses on keeping a close eye on our investments, making sure everything is accounted for and managed properly.

6. Reviewing Performance: The last step involves regularly checking how our trades are doing, and evaluating if our strategy meets our goals.

Further Exploration:

Conclusion: By simplifying this process into manageable steps, this tutorial offers a straightforward path to developing, implementing, and refining a trading strategy.

1. Trading Strategy Definition

The trend strategy is designed for trading within the S&P 500 energy sector stocks. It utilizes moving averages as indicators to capture market trends and guide trading decisions.

1. Indicator Generation:

  • Fast Moving Average (FMA): A 20-day moving average that reacts quickly to price changes, indicating short-term price trends.
  • Slow Moving Average (SMA): A 40-day moving average that smoothens out price data over a longer period, showing longer-term price direction.

The use of two moving averages helps to identify the momentum and direction of stock prices by comparing short-term price movements to longer-term trends.

2. Trading Signal Criteria and Trade Execution:

We now see how positions are opened, managed, and closed:

Opening Positions:

  1. Long Positions (Buying):
    • Entry Signal: Initiate a buy order when the current stock price moves above both the Fast Moving Average (FMA) and Slow Moving Average (SMA).
    • Rationale: Crossing above both moving averages suggests a strong upward trend, indicating a potential for profit from rising prices.
  2. Short Positions (Selling Short):
    • Entry Signal: Enter a sell short order when the current stock price drops below both the FMA and SMA.
    • Rationale: Falling below both averages signals a strong downward trend, presenting an opportunity to profit from declining stock prices.

Holding and Monitoring Positions:

  • After entering a position, it is held until the exit criteria, based on moving averages, signal a potential change in the trend direction.

Closing Positions:

  1. Exiting Long Positions:
    • Exit Signal: Close out (sell) the long position when the current price falls below either the FMA or SMA.
    • Rationale: Dropping below either moving average may indicate the upward trend is losing momentum, warranting an exit to protect profits or minimize losses.
  2. Exiting Short Positions:
    • Exit Signal: Cover (buy back) the short position when the current price rises above either the FMA or SMA.
    • Rationale: Rising above either average suggests the downward trend may be weakening, prompting an exit to capture gains from the short sale or to reduce potential losses.

2. Setting Parameters

The above R script snippet is setting up an environment for financial data analysis by loading libraries for technical analysis and visualization. It also includes steps to define the working directory, and clear the workspace to start with a clean slate.

The code loads a 5-year financial dataset and sector information, specifically focusing on the Energy sector’s stocks from 2021 to 2023. It sets the trading strategy’s initial capital at $100,000, limits trades to $5,000 each, and restricts to 8 trades per day.

3. Generating Indicators :

The genIndicators function (lines 40-68) is designed to process financial time series data for a given stock symbol. It begins by announcing the symbol being analyzed (line 42), the core of this function focuses on extracting the subset of data corresponding to the chosen stock symbol (line 44) and converting it into a time series object suitable for technical analysis (line 45).

Once the data is in the correct format, the function establishes the commencement point for backtesting by setting a start date (line 47). This date acts as the anchor from which historical data is evaluated, and is also used to identify the index position within the data where the backtesting should begin (line 48). The function then prepares the analytical environment by initializing vectors that will hold the predicted returns, prediction confidence percentages, and determined trade types — either long or short positions (lines 49-52).

The next segment of the function (lines 53-62) iteratively processes the historical data. For each time period within the backtesting range, it employs a loop to fit an ETS model to the stock’s closing prices observed within a specified window (lines 54-56). The function is equipped to handle potential errors during the ETS model fitting process gracefully, using a try-catch mechanism to avoid execution interruptions (line 56). Following a successful model fit, a forecast is generated for the subsequent time period (lines 57-58), from which the predicted return is calculated (line 59). These predictions form the basis for the trading signals, determining whether to take a long or short position based on whether the predicted closing price is higher or lower than the last observed closing price (lines 60-61).

Finally, the function compiles the results into a structured data frame (line 65), which includes the trade date, symbol, and the newly generated indicators and signals. This output is then filtered to retain only the data relevant for the backtesting period (lines 66-67), providing a clean and focused dataset for evaluating the trading strategy. The return of the filtered data frame (line 68) marks the completion of the indicator generation process, supplying the necessary inputs for the subsequent stages of backtesting the trading strategy. ## 3. Merge the daily data with our new universe and apply relevant transformations.

4. Strategy Execution Rules:

The applyRules function within the script performs the role of identifying which trades to make based on specified rules and the equity available on a given trading day.

When this function is called, it starts by subsetting the universe of stocks to find those that meet specific conditions: the date must match the day parameter passed to the function, the absolute predicted return must be greater than or equal to a minimum threshold, and the prediction confidence must be below a certain threshold (lines 72-73). This ensures only the most promising stocks on that particular day are considered for trading.

The potential trades are then divided into two groups: long position candidates and short position candidates, based on the predicted trade type (lines 74-75). To avoid overexposure, the function enforces a cap on the maximum number of long and short positions that can be held at once, selecting the top candidates by their predicted return percentage within each group (lines 76-77).

Once the individual long and short candidates are determined, they are combined into a single list of candidates (line 78). This combined list is then ordered by predictability, and only the top candidates up to the maximum number of trades allowed for the day are kept (line 79).

The function proceeds to calculate the investment amount for each trade. It allocates the available equity to each candidate based on its predictability score, ensuring no individual trade exceeds the maximum trade size limit (line 83). Buy and sell prices are set depending on whether the trade is a long or a short position, impacting how the returns are calculated for each trade (lines 85-86).

The function then tallies the total amount invested across all candidates (line 88) and computes the portfolio’s weighted return, taking into account the proportion of each investment (line 89). The equity is updated to reflect the returns from the trades made, indicating the new portfolio value after the trades (lines 90-91).

In cases where no trades are to be made, the function sets the total investment, total return, and cashout values to reflect a state of no change (lines 93-96).

Finally, applyRules returns a list that includes details of the trades executed, the amount of cash invested, the cashout from these trades, and the total return on the day’s equity (line 98). This output gives a clear picture of the day’s trading activity, the effectiveness of the strategy, and its impact on the equity available for future trades.

5. Portfolio Management and Evaluation:

The portfolioStats function (lines 103-150) is a comprehensive tool within the trading strategy’s script for analyzing and summarizing the performance of a trading portfolio. The function begins by determining the frequency of trade activity, assessing the number of days trades were made (line 104) against the total number of days in the trading period (line 105). It then calculates the proportion of days that included trading activities (line 106). Understanding the volume of trades executed, the function separates these into long (line 108) and short (line 109) positions, providing a clear perspective on trading directions undertaken.

Further analysis within the function measures the success rates of these trades. It determines the percentage of profitable trades from both long (line 110) and short (line 111) positions, as well as their average returns (lines 112-113). This insight is crucial for evaluating the strategy’s effectiveness. The overall win rate across all trades is also computed (line 114), giving a straightforward metric of the strategy’s success.

The function next computes the cumulative return of the portfolio (line 115) and identifies the maximum return achieved at any point (line 116), which can signal the portfolio’s peak performance. It also assesses the risk by calculating the maximum drawdown—a measure of the largest single drop from peak to trough in the portfolio’s value (line 117)—and the duration of the longest drawdown period (lines 118-119), providing a view into the potential volatility and risks encountered.

To capture the average performance and adjust it for risk, the function calculates the mean return (line 120) and the Sharpe ratio (line 121), the latter of which normalizes the return by the portfolio’s volatility, giving a sense of the risk-adjusted return.

Visually, the function then plots the performance over time (lines 122-129), using different colors to distinguish between cumulative returns, the maximum return, and the actual portfolio return. This graphical representation, complemented by a legend (lines 128-129), serves as a quick visual summary of performance trends and significant milestones.

Finally, all these statistical measures are compiled into a list (lines 130-146), which is returned from the function. This list serves as a comprehensive performance report, encapsulating key metrics such as trade counts, win rates, average returns, drawdowns, and the Sharpe ratio. By presenting these metrics cohesively, the portfolioStats function offers a detailed overview of the portfolio’s historical performance, enabling traders or analysts to make informed decisions based on past outcomes.

6. Performance Assessment:

The code snippet is part of a script designed to run a trading strategy from start to finish. It commences by aggregating indicators for various stocks into a single data frame (stock), ensuring no row names are carried over for clarity (lines 152-155). It then establishes a set of unique trading days (tdays) and initializes the equity (currentequity) to the predefined starting value (lines 156-157). To facilitate daily trade analysis, the code prepares a list (trades_list) and a numeric vector (preturn) to store trade data and portfolio returns for each trading day, respectively (lines 158-159).

A loop is then initiated, iterating over each trading day. Within this loop, the applyRules function is called for the current date and equity balance (lines 161-163). If trades are returned for the day, the code ensures they are marked with the correct date (lines 164-165). These trades are then added to the trades_list, and the equity is adjusted based on the day’s cash flows (lines 166-168). The portfolio return for the day is recorded (line 169).

After processing all trading days, the individual day’s trades are consolidated into a single data frame (trades) (line 170). The final step involves calculating the strategy’s performance statistics by calling the portfolioStats function and storing its output (lines 173-174). This output (performance) represents a comprehensive assessment of the strategy’s success over the evaluated period, reflecting key performance indicators such as return on investment, win rates, and risk metrics.

Conclusion:

Based on the above results, we can conclude that the trading strategy implemented has experienced a mix of outcomes over the assessed period. The portfolio results indicate a total of 1750 trades, with nearly half of them (998) being long positions and the remaining 752 being short positions. While the strategy had a slightly higher success rate with long trades (51.002%) compared to short trades (47.2045%), both types of trades have resulted in negative average returns, as shown by the avg_return_long and avg_return_short values.

The overall winning percentage of trades stands at approximately 49.37%, which is close to being evenly split between winning and losing trades. The cumulative return of the portfolio suggests a slight decline over time, ending below the starting equity, as the cumulative return dips to about 0.9239 of the initial value.

The Sharpe ratio is negative, indicating that the risk-adjusted return of the portfolio is below the risk-free rate of return over the period. This could be interpreted as the portfolio not providing enough return to justify the risk taken on by the investments. Furthermore, the maximum drawdown experienced by the portfolio is substantial, at -12.82167%, with the longest drawdown period lasting for 676 time periods, suggesting significant volatility and potential sustained periods of losses.

The accompanying graph visualizes these statistics by showing the cumulative return in comparison to the maximum return and the actual portfolio return over time. The decline in the cumulative return line and its deviation from the max return line illustrate the challenges the strategy faced in maintaining and growing the initial equity.

In summary, while the strategy has had a nearly equal proportion of winning to losing trades, the negative average returns and the overall decline in equity signify that the strategy may require re-evaluation and adjustment to improve its performance and to better manage risk and drawdowns.