Add ATR regime backtest filter

This commit is contained in:
moshferatu 2024-07-29 11:52:10 -07:00
parent 0c92789d26
commit d27b0e301c
4 changed files with 112 additions and 0 deletions

43
atr_regime_backtest.py Normal file
View File

@ -0,0 +1,43 @@
from datetime import datetime
from dotenv import load_dotenv
from os import getenv
from pandas import concat
from backtesting import backtest_iron_condor
from backtesting.credit_targeting import create_strategies
from backtesting.filter import ATRRegimeFilter
from plotting import BacktestChart, plot
load_dotenv()
if __name__ == '__main__':
start_date = datetime(2016, 1, 1)
end_date = datetime.now()
credit_target = float(getenv('CREDIT_TARGET'))
entry_times = getenv('ENTRY_TIMES').split(',')
backtest_results = []
for entry_time in entry_times:
call_spread_strategy, put_spread_strategy = create_strategies(credit_target, entry_time)
backtest_result = backtest_iron_condor(
f'${credit_target:.2f} Iron Condor @ {call_spread_strategy.trade_entry_time}',
call_spread_strategy,
put_spread_strategy,
start_date,
end_date,
filters = [ATRRegimeFilter()]
)
backtest_results.append(backtest_result)
combined_backtest_results = concat(backtest_results)
summed_results = combined_backtest_results.groupby('Date')['Cumulative Profit'].sum().reset_index()
plot(BacktestChart(
dates = summed_results['Date'],
profit = summed_results['Cumulative Profit'],
title = f'${credit_target:.2f} Iron Condor (ATR Regime Filter)'
))

View File

@ -1,3 +1,4 @@
from .atr_regime_filter import ATRRegimeFilter
from .backtest_filter import BacktestFilter
from .volatility_regime_filter import VolatilityRegimeFilter
from .vvix_regime_filter import VVIXRegimeFilter

View File

@ -0,0 +1,64 @@
import numpy as np
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 ATRRegimeFilter(BacktestFilter):
def __init__(self):
self.backtest_filter = self.filter()
def calculate_atr(self, high, low, close, period = 5):
tr = np.maximum(high - low, np.abs(high - close.shift(1)), np.abs(low - close.shift(1)))
atr = tr.rolling(window = period).mean()
return atr
def filter(self) -> DataFrame:
data_start_date = datetime.strptime(getenv('OPTION_DATA_START_DATE'), '%Y-%m-%d')
now = datetime.now()
spx_data = ohlc(
symbol = 'SPX.XO',
timeframe = '1d',
start_date = data_start_date - timedelta(weeks = 52),
end_date = now
)
spx_data.rename(columns = {'Timestamp': 'Date'}, inplace = True)
spx_data['ATR'] = self.calculate_atr(spx_data['High'], spx_data['Low'], spx_data['Close'])
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
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.
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
spx_data = concat([
spx_data,
DataFrame({
'Date': [datetime.combine(now, datetime.min.time())],
'Open': [0.0],
'High': [0.0],
'Low': [0.0],
'Close': [0.0],
'Volume': [0.0],
'ATR': [0.0]
})],
ignore_index = True
)
percent_rank = lambda x: Series(x).rank(pct = True).iloc[-1]
spx_data['ATR_Percent_Rank'] = spx_data['ATR'].shift(1).rolling(window = 252).apply(percent_rank)
filtered_data = spx_data[spx_data['Date'] >= data_start_date].copy()
# filtered_data['Trade Allowed'] = (filtered_data['ATR_Percent_Rank'] > 0.25) & (filtered_data['ATR_Percent_Rank'] < 0.75)
filtered_data['Trade Allowed'] = filtered_data['ATR_Percent_Rank'] < 0.75
filtered_data = filtered_data[['Date', 'Trade Allowed']].reset_index(drop = True)
return filtered_data

View File

@ -0,0 +1,4 @@
from backtesting.filter import ATRRegimeFilter
filter = ATRRegimeFilter()
print(filter.backtest_filter)