7.3 KiB
This code downloads historical price data for the TLT ETF and generates trading signals based on calendar rules. It sets up short and long entry and exit signals, such as entering a short position on the first day of each month and exiting five days later. The code also defines a function to simulate a trading strategy and calculate performance metrics, specifically the Sharpe ratio. Finally, it runs this strategy on shuffled data to generate a distribution of Sharpe ratios for comparison. This approach aids in evaluating the robustness and statistical significance of the trading strategy.
import pandas as pd import numpy as np import matplotlib.pyplot as plt import vectorbt as vbt
Download historical price data for TLT ETF from Yahoo Finance and extract the closing prices
tlt = vbt.YFData.download( "TLT", start="2004-01-01" ).get("Close").to_frame() close = tlt.Close
Set up empty dataframes to hold trading signals for short and long positions
short_entries = pd.DataFrame.vbt.signals.empty_like(close) short_exits = pd.DataFrame.vbt.signals.empty_like(close) long_entries = pd.DataFrame.vbt.signals.empty_like(close) long_exits = pd.DataFrame.vbt.signals.empty_like(close)
Generate short entry signals on the first day of each new month
short_entry_mask = ~tlt.index.tz_convert(None).to_period("M").duplicated() short_entries.iloc[short_entry_mask] = True
Generate short exit signals five days after short entry
short_exit_mask = short_entries.shift(5).fillna(False) short_exits.iloc[short_exit_mask] = True
Generate long entry signals seven days before the end of each month
long_entry_mask = short_entries.shift(-7).fillna(False) long_entries.iloc[long_entry_mask] = True
Generate long exit signals one day before the end of each month
long_exit_mask = short_entries.shift(-1).fillna(False) long_exits.iloc[long_exit_mask] = True
Define a function to simulate the trading strategy and calculate performance metrics
def run_sim(close): """Simulate trading strategy This function simulates a trading strategy based on given entry and exit signals. Parameters ---------- close : pd.Series The closing prices of the asset. Returns ------- pf : vbt.Portfolio The simulated portfolio. """ return vbt.Portfolio.from_signals( close=close, entries=long_entries, exits=long_exits, short_entries=short_entries, short_exits=short_exits, freq="1d" )
Run the simulation and calculate the Sharpe ratio for the trading strategy
pf = run_sim(close) sr = pf.sharpe_ratio() pf.stats()
Run the simulation on shuffled data 1000 times to generate a distribution of Sharpe ratios
sharpes = [] for i in range(1000): shuffled_close = close.sample(frac=1) shuffled_close.index = close.index shuffled_sharpe = run_sim(shuffled_close).sharpe_ratio() sharpes.append(shuffled_sharpe)
Plot the distribution of simulated Sharpe ratios and mark the original strategy's Sharpe ratio
pd.DataFrame( sharpes, columns=["Simulated Sharpe Ratios"] ).hist( bins=np.histogram_bin_edges(sharpes, bins="fd") ) plt.axvline(sr, linestyle="dashed", linewidth=1) min_ylim, max_ylim = plt.ylim() plt.text(sr * -0.01, max_ylim * 0.9, f"Strat Sharpe: {sr:.1f}")
PyQuant News is where finance practitioners level up with Python for quant finance, algorithmic trading, and market data analysis. Looking to get started? Check out the fastest growing, top-selling course to get started with Python for quant finance. For educational purposes. Not investment advise. Use at your own risk.
