Department of Artificial Intelligence and Data Science
Experiment No. 5
Aim: To study and implement Backtesting for a simple trading algorithm.
Theory:
Backtesting is the process of testing a trading strategy or model using historical data to evaluate
its performance and determine how it would have performed in the past. It involves applying the
strategy to past market data, running simulations, and analyzing the results to understand how
well the strategy would have worked under specific conditions.
How Backtesting Works:
1. Collect Historical Data: First, you need access to historical price data (e.g., stock prices,
currency exchange rates, etc.), including open, high, low, and close prices, along with other
relevant market indicators (volume, volatility, etc.).
2. Define the Strategy: Specify the rules of the trading strategy you wish to test. This could
include criteria like:
o Entry signals (e.g., buy when a certain moving average crosses above another).
o Exit signals (e.g., sell when a price falls below a certain threshold).
o Risk management rules (e.g., stop-loss or take-profit levels).
3. Simulate the Strategy: Apply the trading strategy to the historical data, making buy and
sell decisions based on the defined rules. The simulation will calculate how the strategy
would have performed in terms of profits, losses, and other metrics.
4. Analyze the Results: After running the backtest, you analyze the outcomes. Some common
performance metrics include:
o Total Return: How much the strategy would have earned or lost over the testing
period.
o Sharpe Ratio: Measures the risk-adjusted return.
o Maximum Drawdown: The largest loss from peak to trough.
o Win Rate: The percentage of profitable trades.
How Backtesting Can Be Used in Trading:
1. Strategy Validation: Before deploying a strategy in live markets, backtesting helps
validate its effectiveness. It shows whether the strategy has historically been profitable
or not and provides insights into potential risks.
2. Optimization: By running backtests with different parameters (e.g., adjusting moving
averages, stop-loss levels, etc.), traders can fine-tune their strategies to maximize
performance.
3. Risk Management: Backtesting allows traders to assess the potential risks of a
strategy, such as maximum drawdown or periods of underperformance. This helps them
decide whether the strategy is worth implementing and if the risk is acceptable.
4. Strategy Comparison: Traders can compare multiple strategies and choose the one
with the best performance history, or even combine multiple strategies for better results.
Department of Artificial Intelligence and Data Science
5. Confidence Building: By seeing how a strategy would have performed in the past,
traders can gain more confidence in using it in real-time trading. However, past
performance is not always indicative of future results, so live testing is also necessary.
Historical Data
Backtesting relies heavily on historical market data, which can include:
Price data: Historical open, high, low, and close prices (OHLC).
Volume data: The number of shares or contracts traded.
Fundamental data: Earnings, revenues, and other company or economic data.
Timeframes: The data can be at different time granularities (e.g., minute, hourly, daily,
weekly, monthly).
Position Sizing and Risk Management
Backtesting should account for position sizing (how much of the asset is purchased) and risk
management:
Fixed position size: Buying a fixed number of shares or contracts per trade.
Risk per trade: Defining the maximum risk for each trade (e.g., 1% of the portfolio).
Stop-loss and Take-profit: Backtests can simulate the use of stop-loss and take-profit
orders to manage risks on each trade.
Performance Metrics
Total Return: The total percentage gain or loss over the testing period.
Annualized Return: The return per year, normalized to account for different
backtesting periods.
Maximum Drawdown: The largest peak-to-trough decline in value during the testing
period. It measures the worst-case loss.
Sharpe Ratio: Measures the risk-adjusted return of a strategy. It is the ratio of the
return above the risk-free rate to the standard deviation of the strategy’s return.
Profit Factor: The ratio of gross profit to gross loss. A value greater than 1 indicates
a profitable strategy.
Volatility: The degree of variation in the strategy’s returns, which can help assess the
risk of the strategy.
Challenges
Overfitting: There's a risk of overfitting the strategy to past data, which can lead to
misleading results. A strategy that works well on historical data may not necessarily
perform well in live markets.
Data Quality: Inaccurate or incomplete historical data can lead to erroneous backtest
results.
Market Changes: Market conditions can change over time. A strategy that worked
well in the past may not work in the future due to changes in volatility, liquidity, or
other market dynamics.
Conclusion: Hence we studies and implement backtesting.
3/11/25, 10:11 AM Untitled25
In [6]: import pandas as pd
import [Link] as plt
file_path = "C:\\Users\\HP RGIT3\\Downloads\\yahoo_data.csv"
data = pd.read_csv(file_path, parse_dates=True, index_col='Date')
In [7]: print([Link]())
Open High Low Close Adj Close** \
Date
2023-04-28 33,797.43 34,104.56 33,728.40 34,098.16 34,098.16
2023-04-27 33,381.66 33,859.75 33,374.65 33,826.16 33,826.16
2023-04-26 33,596.34 33,645.83 33,235.85 33,301.87 33,301.87
2023-04-25 33,828.34 33,875.49 33,525.39 33,530.83 33,530.83
2023-04-24 33,805.04 33,891.15 33,726.09 33,875.40 33,875.40
Volume
Date
2023-04-28 35,43,10,000
2023-04-27 34,32,40,000
2023-04-26 32,11,70,000
2023-04-25 29,78,80,000
2023-04-24 25,20,20,000
In [9]: data['Close'] = data['Close'].replace({',': ''}, regex=True).astype(float)
# Now calculate moving averages
short_window = 50
long_window = 200
data['Short_MA'] = data['Close'].rolling(window=short_window).mean()
data['Long_MA'] = data['Close'].rolling(window=long_window).mean()
In [10]: data['Signal'] = 0 # Default value is no signal
data['Signal'][short_window:] = (data['Short_MA'][short_window:] > data['Lo
ng_MA'][short_window:]).astype(int)
C:\Users\HP RGIT3\Anaconda3\lib\site-packages\ipykernel_launcher.py:2: Set
tingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: [Link]
s/stable/[Link]#indexing-view-versus-copy
In [11]: data['Position'] = data['Signal'].diff()
In [12]: initial_cash = 10000
data['Cash'] = initial_cash
data['Shares'] = 0
data['Portfolio_Value'] = initial_cash
[Link] RGIT3/Downloads/[Link] 1/3
3/11/25, 10:11 AM Untitled25
In [13]: for i in range(1, len(data)):
if data['Position'].iloc[i] == 1: # Buy Signal
data['Shares'].iloc[i] = data['Cash'].iloc[i-1] / data['Close'].ilo
c[i]
data['Cash'].iloc[i] = 0
elif data['Position'].iloc[i] == -1: # Sell Signal
data['Cash'].iloc[i] = data['Shares'].iloc[i-1] * data['Close'].ilo
c[i]
data['Shares'].iloc[i] = 0
data['Portfolio_Value'].iloc[i] = data['Cash'].iloc[i] + (data['Share
s'].iloc[i] * data['Close'].iloc[i])
C:\Users\HP RGIT3\Anaconda3\lib\site-packages\pandas\core\[Link]:
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: [Link]
s/stable/[Link]#indexing-view-versus-copy
self._setitem_with_indexer(indexer, value)
[Link] RGIT3/Downloads/[Link] 2/3
3/11/25, 10:11 AM Untitled25
In [16]: # Plot Stock Price and Moving Averages with Buy/Sell Signals
[Link](figsize=(12, 6))
# Plot the closing price
[Link](data['Close'], label='Stock Price', color='blue')
# Plot the short-term (50-day) moving average
[Link](data['Short_MA'], label='50-Day Moving Average', color='red', alph
a=0.7)
# Plot the long-term (200-day) moving average
[Link](data['Long_MA'], label='200-Day Moving Average', color='green', al
pha=0.7)
# Plot Buy Signals (Green Up Arrows)
[Link](data[data['Position'] == 1].index, data['Close'][data['Position']
== 1], '^', markersize=10, color='green', lw=0, label='Buy Signal')
# Plot Sell Signals (Red Down Arrows)
[Link](data[data['Position'] == -1].index, data['Close'][data['Position']
== -1], 'v', markersize=10, color='red', lw=0, label='Sell Signal')
# Add title and labels
[Link]('Stock Price with Buy/Sell Signals and Moving Averages', fontsize
=16)
[Link]('Date')
[Link]('Price ($)')
[Link](loc='best')
# Show the plot
[Link]()
In [ ]:
[Link] RGIT3/Downloads/[Link] 3/3