Code part by part explanations and use case
Full Code :
import pandas as pd
import yfinance as yf
import numpy as npdef download_stock_data(symbol, start_date, end_date):
stock_data = yf.download(symbol, start=start_date, end=end_date)
return stock_data
def generate_signals(data):
signals = pd.DataFrame(index=data.index)
signals['signal'] = 0.0
print(data)
# Create a short simple moving average over the short window
signals['short_mavg'] = data['Close'].rolling(window=40, min_periods=1, center=False).mean()
# Create a long simple moving average over the long window
signals['long_mavg'] = data['Close'].rolling(window=100, min_periods=1, center=False).mean()
# Create signals
signals['signal'][40:] = np.where(signals['short_mavg'][40:] > signals['long_mavg'][40:], 1.0, 0.0)
# Generate trading orders
signals['positions'] = signals['signal'].diff()
return signals
def backtest_strategy(signals, initial_capital=100000):
positions = pd.DataFrame(index=signals.index).fillna(0.0)
positions['stock'] = 100 * signals['signal'] # Buy 100 shares on each buy signal
# Initialize the portfolio with value owned
portfolio = positions.multiply(data['Adj Close'], axis=0)
# Store the difference in shares owned
pos_diff = positions.diff()
# Add 'cash' to portfolio
portfolio['cash'] = initial_capital - (pos_diff.multiply(data['Adj Close'], axis=0)).c*msum()
# Add 'total' to portfolio
portfolio['total'] = portfolio['cash'] + portfolio['stock']
return portfolio
if __name__ == "__main__":
symbol = 'AAPL'
start_date = '2022-01-01'
end_date = '2023-01-01'
# Download historical stock data
data = download_stock_data(symbol, start_date, end_date)
# Generate trading signals
signals = generate_signals(data)
# Backtest the trading strategy
portfolio = backtest_strategy(signals)
# Print the portfolio
display(portfolio)
Sure, let’s break down the provided Python code step by step:
- Import necessary libraries:
Use Case:
import pandas as pd
: Imports the Pandas library and aliases it aspd
for easier reference.import yfinance as yf
: Imports the Yahoo Finance library and aliases it asyf
.import numpy as np
: Imports the NumPy library and aliases it asnp
.
import pandas as pd
import yfinance as yf
import numpy as np
Explanation:
pandas
: A library for data manipulation and analysis.yfinance
: A library for downloading financial data from Yahoo Finance.numpy
: A library for numerical operations.
2. Define a function to download historical stock data:
Use Case:
def download_stock_data(symbol, start_date, end_date):
: Defines a function nameddownload_stock_data
that takes a stock symbol, start date, and end date as parameters.stock_data = yf.download(symbol, start=start_date, end=end_date)
: Uses theyfinance
library to download historical stock data for the specified symbol and time period.return stock_data
: Returns the downloaded stock data as a Pandas DataFrame.
def download_stock_data(symbol, start_date, end_date):
stock_data = yf.download(symbol, start=start_date, end=end_date)
return stock_data
Explanation:
- This function takes a stock symbol, start date, and end date as parameters.
- It uses
yfinance
to download historical stock data for the specified symbol and time period. - Returns a Pandas DataFrame containing the stock data.
3. Define a function to generate trading signals:
Use Case:
def generate_signals(data):
: Defines a function namedgenerate_signals
that takes a DataFrame of stock data as input.signals = pd.DataFrame(index=data.index)
: Creates a DataFrame namedsignals
with the same index as the input data.signals['signal'] = 0.0
: Adds a column 'signal' initialized with zeros.- The following lines calculate short and long simple moving averages and generate buy (1.0) and sell (0.0) signals based on a crossover strategy.
signals['positions'] = signals['signal'].diff()
: Creates a column 'positions' representing the trading positions by taking the difference of consecutive signals.
def generate_signals(data):
signals = pd.DataFrame(index=data.index)
signals['signal'] = 0.0
# Create a short simple moving average over the short window
signals['short_mavg'] = data['Close'].rolling(window=40, min_periods=1, center=False).mean()
# Create a long simple moving average over the long window
signals['long_mavg'] = data['Close'].rolling(window=100, min_periods=1, center=False).mean()
# Create signals
signals['signal'][40:] = np.where(signals['short_mavg'][40:] > signals['long_mavg'][40:], 1.0, 0.0)
# Generate trading orders
signals['positions'] = signals['signal'].diff()
return signals
Explanation:
- This function generates trading signals based on a simple moving average crossover strategy.
- It calculates short and long simple moving averages using the closing prices.
- Buy signal (1.0) is generated if short-term MA > long-term MA; otherwise, a sell signal (0.0) is generated.
- The ‘positions’ column represents the trading positions.
4. Define a function to backtest the trading strategy:
Use Case:
def backtest_strategy(signals, initial_capital=100000):
: Defines a function namedbacktest_strategy
that takes trading signals and an initial capital amount as input.- The function simulates trading by creating a DataFrame
positions
representing the trading positions and calculates the resulting portfolio. portfolio['total'] = portfolio['cash'] + portfolio['stock']
: Computes the total portfolio value by summing the cash and stock values.
def backtest_strategy(signals, initial_capital=100000):
positions = pd.DataFrame(index=signals.index).fillna(0.0)
positions['stock'] = 100 * signals['signal'] # Buy 100 shares on each buy signal
# Initialize the portfolio with value owned
portfolio = positions.multiply(data['Adj Close'], axis=0)
# Store the difference in shares owned
pos_diff = positions.diff()
# Add 'cash' to portfolio
portfolio['cash'] = initial_capital - (pos_diff.multiply(data['Adj Close'], axis=0)).c*msum()
# Add 'total' to portfolio
portfolio['total'] = portfolio['cash'] + portfolio['stock']
return portfolio
Explanation:
- This function backtests the trading strategy using the generated signals.
- It creates a DataFrame (
positions
) to represent trading positions (buying 100 shares on each buy signal). - Initializes the portfolio with the value of the owned stock.
- The difference in shares owned is stored (
pos_diff
). - ‘cash’ column represents remaining cash after buying or selling shares.
- ‘total’ column represents the total portfolio value.
5. The main section of the code:
Use Case:
if __name__ == "__main__":
: Checks if the script is being run directly (not imported as a module).symbol = 'AAPL'
,start_date = '2022-01-01'
,end_date = '2023-01-01'
: Defines the stock symbol and date range for downloading historical data.- Calls the
download_stock_data
function to get historical stock data. - Generates trading signals using the
generate_signals
function. - Backtests the trading strategy using the
backtest_strategy
function. - Displays the resulting portfolio using the
display
function. Note: Make sure thedisplay
function is properly imported or replace it withprint
if needed.
if __name__ == "__main__":
symbol = 'AAPL'
start_date = '2022–01–01'
end_date = '2023–01–01'
# Download historical stock data
data = download_stock_data(symbol, start_date, end_date)
# Generate trading signals
signals = generate_signals(data)
# Backtest the trading strategy
portfolio = backtest_strategy(signals)
# Print the portfolio
display(portfolio)
Explanation:
- This section is executed if the script is run directly.
- Specifies stock symbol (‘AAPL’) and date range for downloading historical data.
- Downloads historical stock data, generates trading signals, backtests the strategy, and displays the resulting portfolio.
In summary, this script downloads historical stock data, generates trading signals based on a simple moving average crossover strategy, and backtests the strategy by simulating the execution of buy and sell orders. The final portfolio values are then displayed.