From a804dcc7b1b078f5fe5e5d51d9b315c9452ae566 Mon Sep 17 00:00:00 2001 From: moshferatu Date: Sun, 12 May 2024 05:07:29 -0700 Subject: [PATCH] Add VVIX regime filter for backtesting options --- backtesting/filter/__init__.py | 3 +- backtesting/filter/vvix_regime_filter.py | 55 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 backtesting/filter/vvix_regime_filter.py diff --git a/backtesting/filter/__init__.py b/backtesting/filter/__init__.py index 6fd6e80..f7e8bb1 100644 --- a/backtesting/filter/__init__.py +++ b/backtesting/filter/__init__.py @@ -1,2 +1,3 @@ from .backtest_filter import BacktestFilter -from .volatility_regime_filter import VolatilityRegimeFilter \ No newline at end of file +from .volatility_regime_filter import VolatilityRegimeFilter +from .vvix_regime_filter import VVIXRegimeFilter \ No newline at end of file diff --git a/backtesting/filter/vvix_regime_filter.py b/backtesting/filter/vvix_regime_filter.py new file mode 100644 index 0000000..5c72a08 --- /dev/null +++ b/backtesting/filter/vvix_regime_filter.py @@ -0,0 +1,55 @@ +from datetime import datetime, timedelta +from dotenv import load_dotenv +from os import getenv +from pandas import concat, DataFrame, Series + +from database.ohlc import ohlc + +from .backtest_filter import BacktestFilter + +load_dotenv() + +class VVIXRegimeFilter(BacktestFilter): + + def __init__(self): + self.backtest_filter = self.filter() + + def filter(self) -> DataFrame: + data_start_date = datetime.strptime(getenv('OPTION_DATA_START_DATE'), '%Y-%m-%d') + + now = datetime.now() + vvix_data = ohlc( + symbol = 'VVIX.XO', + timeframe = '1d', + start_date = data_start_date - timedelta(weeks = 52), + end_date = now + ) + + vvix_data.rename(columns = {'Timestamp': 'Date'}, inplace = True) + + """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + Filtering is based on the previous day's close, so the current date can be included even though the + data may not be availble yet. + + This allows for utilizing the filter in live trading to decide whether to trade prior to market open. + """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + vvix_data = concat([ + vvix_data, + DataFrame({ + 'Date': [datetime.combine(now, datetime.min.time())], + 'Open': [0.0], + 'High': [0.0], + 'Low': [0.0], + 'Close': [0.0], + 'Volume': [0.0] + })], + ignore_index = True + ) + + percent_rank = lambda x: Series(x).rank(pct = True).iloc[-1] + vvix_data['Percent Rank'] = vvix_data['Close'].shift(1).rolling(window = 252).apply(percent_rank) + + filtered_data = vvix_data[vvix_data['Date'] >= data_start_date].copy() + filtered_data['Trade Allowed'] = filtered_data['Percent Rank'] < 0.50 + filtered_data = filtered_data[['Date', 'Trade Allowed']].reset_index(drop = True) + return filtered_data \ No newline at end of file