[Python] Any fix for start date in Quantstats?

Discussão em 'Python' iniciado por Stack, Abril 29, 2025.

  1. Stack

    Stack Membro Participativo

    I'm trying to backtest some investment strategies in python through QuantStats. The problem is that my analysis, independently from the year I choose, starts from 4th February despite setting the start date at 1/1/year. How can I fix this?

    import numpy as np
    import pandas as pd
    from datetime import datetime, timedelta
    import yfinance as yf
    import quantstats as qs
    qs.extend_pandas()
    import matplotlib.pyplot as plt

    equity_etfs = ['VTI','IEF']
    stock_frames = []
    stock_daily_frames = []

    for tick in equity_etfs:
    data = yf.download(tick, start="2013-01-01", end="2023-12-31", group_by='ticker', interval='1d')
    data = data[['Adj Close']]
    data = data.rename(columns={'Adj Close': tick})
    stock_daily_frames.append(data)

    equity_daily_returns = pd.concat(stock_daily_frames, axis=1)
    equity_daily_returns = equity_daily_returns.pct_change().dropna()
    equity_daily_returns = equity_daily_returns.dropna()

    def calculate_60_40_strategy(daily_returns, name='60/40 Strategy'):
    daily_returns.index = pd.to_datetime(daily_returns.index)

    daily_returns[name] = np.nan

    weights = {'VTI': 0.6, 'IEF': 0.4}

    for month_end in daily_returns.resample('M').last().index:
    start_of_next_month = month_end + pd.DateOffset(days=1)
    end_of_next_month = start_of_next_month + pd.DateOffset(months=1) - pd.DateOffset(days=1)
    mask = (daily_returns.index >= start_of_next_month) & (daily_returns.index <= end_of_next_month)
    daily_returns.loc[mask, name] = daily_returns.loc[mask, ['VTI', 'IEF']].dot(pd.Series(weights))

    daily_returns[name].fillna(method='ffill', inplace=True)

    return daily_returns

    def calculate_60_40_strategy(daily_returns, fees=0, name='60/40 Strategy'):
    daily_returns.index = pd.to_datetime(daily_returns.index)

    daily_returns[name] = np.nan

    weights = {'VTI': 0.6, 'IEF': 0.4}

    first_month = True

    for month_end in daily_returns.resample('M').last().index:
    start_of_next_month = month_end + pd.DateOffset(days=1)
    end_of_next_month = start_of_next_month + pd.DateOffset(months=1) - pd.DateOffset(days=1)
    mask = (daily_returns.index >= start_of_next_month) & (daily_returns.index <= end_of_next_month)

    if not first_month:
    daily_returns.loc[mask, name] = (daily_returns.loc[mask, ['VTI', 'IEF']].dot(pd.Series(weights))) * (1 - fees)
    else:
    daily_returns.loc[mask, name] = daily_returns.loc[mask, ['VTI', 'IEF']].dot(pd.Series(weights))
    first_month = False

    daily_returns[name].fillna(method='ffill', inplace=True)

    return daily_returns

    fee_levels = [0, 0.01, 0.03, 0.05]

    for fee in fee_levels:
    strategy_name = f"60/40 fees={fee}"
    calculate_60_40_strategy(equity_daily_returns, fees=fee, name=strategy_name)

    cumulative_returns = (1 + equity_daily_returns.filter(like="60/40")).cumprod()

    plt.figure(figsize=(12, 6))
    for column in cumulative_returns.columns:
    plt.plot(cumulative_returns.index, cumulative_returns[column], label=column)

    plt.title("Cumulative Returns of 60/40 Strategy with Different Fees")
    plt.xlabel("Date")
    plt.ylabel("Cumulative Returns")
    plt.legend()
    plt.show()

    qs.reports.html(equity_daily_returns['60/40 fees=0'], equity_daily_returns['VTI'], output="60_40_2013_2023 Strategy.html")

    Continue reading...

Compartilhe esta Página