Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
4.9 kB
4
Indexable
Never
import os
import vectorbtpro as vbt
from numba import njit
import numpy as np

import talib

# Define the symbols and date range
symbols = {'BTC-USD': 'Bitcoin', 'TSLA': 'Tesla'}
start_date = '2024-08-01'
end_date = '2024-08-20'

# Define the range of parameters for Supertrend
periods = list(range(5, 51))  # Periods from 5 to 50 with an increment of 1
multipliers = [round(x * 0.01, 2) for x in range(50, 301, 1)]  # Multiplier from 0.5 to 3.0 with an increment of 0.01

# Define the Supertrend logic using Numba and VectorBT's IndicatorFactory
@njit
def get_final_bands_nb(close, upper, lower):
    trend = np.full(close.shape, np.nan)
    dir_ = np.full(close.shape, 1)
    long = np.full(close.shape, np.nan)
    short = np.full(close.shape, np.nan)

    for i in range(1, close.shape[0]):
        if close[i] > upper[i - 1]:
            dir_[i] = 1
        elif close[i] < lower[i - 1]:
            dir_[i] = -1
        else:
            dir_[i] = dir_[i - 1]
            if dir_[i] > 0 and lower[i] < lower[i - 1]:
                lower[i] = lower[i - 1]
            if dir_[i] < 0 and upper[i] > upper[i - 1]:
                upper[i] = upper[i - 1]

        if dir_[i] > 0:
            trend[i] = long[i] = lower[i]
        else:
            trend[i] = short[i] = upper[i]

    return trend, dir_, long, short

def get_basic_bands(med_price, atr, multiplier):
    matr = multiplier * atr
    upper = med_price + matr
    lower = med_price - matr
    return upper, lower

def faster_supertrend_talib(high, low, close, period=7, multiplier=3):
    avg_price = talib.MEDPRICE(high, low)  
    atr = talib.ATR(high, low, close, period)
    upper, lower = get_basic_bands(avg_price, atr, multiplier)
    return get_final_bands_nb(close, upper, lower)


# Create the SuperTrend indicator using IndicatorFactory
SuperTrend = vbt.IF(
    class_name='SuperTrend',
    short_name='st',
    input_names=['high', 'low', 'close'],
    param_names=['period', 'multiplier'],
    output_names=['supert', 'superd', 'superl', 'supers']
).with_apply_func(
    faster_supertrend_talib,
    takes_1d=True,
    period=7,
    multiplier=3
)

# Loop through each symbol
for symbol, name in symbols.items():
    # Format the filename with start and end month/year
    filename = f'{name}_{start_date}_to_{end_date}_daily.csv'
    
    # Check if the file already exists
    # if os.path.exists(filename):
    #     print(f"File {filename} already exists. Skipping download for symbol {symbol}.")
    # else:
    #     # Download the data using YahooFinanceData
    #     yahoo_data = vbt.YFData.pull(symbol, tz="EDT", start=start_date, end=end_date)
    #     # Save the data to a CSV file
    #     yahoo_data.to_csv(filename)
    #     print(f"Downloaded and saved data to {filename}.")
    
    # Load the data from the CSV file using vectorbtpro
    data = vbt.Data.from_csv(filename)

    # Run the SuperTrend indicator with all combinations of periods and multipliers
    supertrend = SuperTrend.run(
        data['High'], data['Low'], data['Close'],
        period=periods, multiplier=multipliers, 
        param_product=True
    )
    
    # Generate signals based on Supertrend crossover
    entries = supertrend.superd == 1
    exits = supertrend.superd == -1
    
    # Run backtests with advanced portfolio management features
    portfolio = vbt.Portfolio.from_signals(
        data['Close'],
        entries,
        exits,
        init_cash=100_000,
        fees=0.001,  # Example trading fees
        slippage=0.001,  # Example slippage
        freq='1D',
        parallel=True  # Enable parallel processing for faster backtesting
    )
    
    # Retrieve and display comprehensive performance metrics
    metrics = {
        'Total Return (%)': portfolio.total_return() * 100,
        'Win Rate (%)': portfolio.win_rate() * 100,
        'Sharpe Ratio': portfolio.sharpe_ratio(),
        'Max Drawdown (%)': portfolio.max_drawdown() * 100,
        'Net Profit ($)': portfolio.net_profit(),
        'Net Profit (%)': portfolio.net_profit(return_pct=True) * 100,
    }
    
    metrics_df = vbt.DataFrame(metrics, index=[symbol])
    print(f"\nMetrics for {name}:")
    print(metrics_df)
    
    # Save the results to a CSV file
    metrics_df.to_csv(f'{name}_supertrend_backtest_results_pro.csv')
    
    # Plot the results
    portfolio.plot().show()
    
    # Compare against Buy and Hold strategy
    buy_and_hold = vbt.Portfolio.from_holding(data['Close'], init_cash=100_000, freq='1D')
    
    # Calculate and print performance metrics for Buy and Hold
    print(f"\nBuy and Hold Performance for {name}:")
    print(buy_and_hold.stats())
    
    # Optionally, plot the comparison
    portfolio['returns'].vbt.plot(trace_kwargs=dict(name=f'{name} Strategy Returns')).show()
    buy_and_hold['returns'].vbt.plot(trace_kwargs=dict(name=f'{name} Buy and Hold Returns')).show()


Leave a Comment