Files
strategy-lab/to_explore/pyquantnews/80_VectorBTFlowEffects.ipynb
David Brazda e3da60c647 daily update
2024-10-21 20:57:56 +02:00

7.3 KiB

No description has been provided for this image

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.

In [ ]:
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

In [ ]:
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

In [ ]:
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

In [ ]:
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

In [ ]:
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

In [ ]:
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

In [ ]:
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

In [ ]:
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

In [ ]:
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

In [ ]:
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

In [ ]:
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.