본문 바로가기

Valuable Information

Graph Neural Networks로 시장 상호작용 모델링하기 주식 간 관계를 이해하는 방법

728x90
반응형

Backtesting Trading Strategies with Python and pandas

Overview

Backtesting is a critical step in evaluating the performance of an investment or trading strategy. By simulating how the strategy would have performed in the past, investors can assess its profitability and identify potential weaknesses. In this tutorial, we’ll explore how to implement a backtesting framework using Python and the pandas library.

We’ll focus on:

  1. Fetching historical data.
  2. Calculating buy/sell signals based on a simple strategy.
  3. Simulating trades.
  4. Analyzing performance metrics.

Prerequisites

Before starting, ensure you have the following installed:

  • Python 3.x
  • Necessary libraries:
    pip install pandas yfinance matplotlib

Step-by-Step Guide

1. Define the Trading Strategy

We will implement a Simple Moving Average (SMA) Crossover Strategy:

  • Buy Signal: When the short-term moving average crosses above the long-term moving average.
  • Sell Signal: When the short-term moving average crosses below the long-term moving average.

2. Fetch Historical Data

Use the yfinance library to get historical stock prices.

Example Code

import yfinance as yf
import pandas as pd

# Fetch historical data
def fetch_data(ticker, start_date, end_date):
    data = yf.download(ticker, start=start_date, end=end_date)
    return data[['Close']]  # Focus on 'Close' prices

# Example usage
data = fetch_data("AAPL", "2020-01-01", "2023-01-01")
print(data.head())

3. Calculate Moving Averages

Calculate the short-term (e.g., 50-day) and long-term (e.g., 200-day) moving averages.

# Add moving averages to the data
def add_moving_averages(data, short_window, long_window):
    data['SMA50'] = data['Close'].rolling(window=short_window).mean()
    data['SMA200'] = data['Close'].rolling(window=long_window).mean()
    return data

# Add SMA columns
data = add_moving_averages(data, 50, 200)
print(data.tail())

4. Generate Buy/Sell Signals

Implement logic to identify crossover points.

# Generate buy and sell signals
def generate_signals(data):
    data['Signal'] = 0
    data.loc[data['SMA50'] > data['SMA200'], 'Signal'] = 1  # Buy signal
    data.loc[data['SMA50'] <= data['SMA200'], 'Signal'] = -1  # Sell signal
    return data

# Apply signals
data = generate_signals(data)
print(data.tail())

5. Simulate Trades

Backtest the strategy by simulating trades based on the signals.

# Simulate trades and calculate returns
def backtest_strategy(data, initial_capital=10000):
    capital = initial_capital
    position = 0
    data['Portfolio'] = capital
    data['Returns'] = data['Close'].pct_change()

    for i in range(1, len(data)):
        if data['Signal'].iloc[i] == 1 and position == 0:  # Buy
            position = capital / data['Close'].iloc[i]
            capital = 0
        elif data['Signal'].iloc[i] == -1 and position > 0:  # Sell
            capital = position * data['Close'].iloc[i]
            position = 0

        # Update portfolio value
        data['Portfolio'].iloc[i] = capital + (position * data['Close'].iloc[i])

    return data

# Backtest
results = backtest_strategy(data)
print(results.tail())

6. Visualize Results

Plot the equity curve and the buy/sell signals.

import matplotlib.pyplot as plt

def plot_results(data):
    plt.figure(figsize=(14, 7))
    plt.plot(data['Close'], label='Stock Price', alpha=0.5)
    plt.plot(data['SMA50'], label='SMA50', linestyle='--')
    plt.plot(data['SMA200'], label='SMA200', linestyle='--')

    # Mark buy/sell points
    buy_signals = data[data['Signal'] == 1]
    sell_signals = data[data['Signal'] == -1]
    plt.scatter(buy_signals.index, buy_signals['Close'], label='Buy Signal', marker='^', color='green')
    plt.scatter(sell_signals.index, sell_signals['Close'], label='Sell Signal', marker='v', color='red')

    plt.title('Trading Strategy Backtest')
    plt.legend()
    plt.show()

# Plot the results
plot_results(results)

7. Evaluate Strategy Performance

Calculate key performance metrics:

  • Total Returns: The overall profit or loss.
  • Maximum Drawdown: The largest drop from peak to trough.
  • Sharpe Ratio: Return-to-risk ratio.
# Evaluate performance
def evaluate_performance(data):
    total_return = (data['Portfolio'].iloc[-1] - data['Portfolio'].iloc[0]) / data['Portfolio'].iloc[0]
    max_drawdown = ((data['Portfolio'] / data['Portfolio'].cummax()) - 1).min()
    sharpe_ratio = data['Returns'].mean() / data['Returns'].std() * (252 ** 0.5)  # Annualized Sharpe Ratio
    return {
        "Total Return": total_return,
        "Max Drawdown": max_drawdown,
        "Sharpe Ratio": sharpe_ratio
    }

# Performance metrics
performance = evaluate_performance(results)
print(performance)

Example Output

  1. Portfolio Value Over Time:

    • Graph showing stock price and portfolio value with buy/sell markers.
  2. Performance Metrics:

    Total Return: 0.35 (35%)
    Max Drawdown: -0.15 (-15%)
    Sharpe Ratio: 1.2

Next Steps

  1. Advanced Strategies: Implement strategies based on technical indicators like RSI or Bollinger Bands.
  2. Optimization: Automate parameter tuning (e.g., SMA windows) using libraries like scipy.optimize.
  3. Real-Time Trading: Transition to real-time trading by integrating with brokers via APIs like Interactive Brokers or Alpaca.

References


With this framework, you can backtest various trading strategies and refine them for improved performance, helping you make data-driven investment decisions.

728x90
반응형