diff --git a/strategies/advances.py b/strategies/advances.py deleted file mode 100644 index ca68a8d..0000000 --- a/strategies/advances.py +++ /dev/null @@ -1,22 +0,0 @@ -from pandas import DataFrame, Series -from daily_data import get_daily_data - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the Advance / Decline Ratio strategy. - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - above_200_ma = data['Close'] > data['Close'].rolling(window = 200).mean() - - start_date = data['Date'].min() - end_date = data['Date'].max() - advances = get_daily_data(symbol = 'IINA.Z', start_date = start_date, end_date = end_date) - declines = get_daily_data(symbol = 'IIND.Z', start_date = start_date, end_date = end_date) - - ratio = advances['Close'] / declines['Close'] - ratio_greater_than_2 = ratio >= 2 - - signals = Series('N', index = data.index) - signals[above_200_ma & ratio_greater_than_2] = 'L' - return signals \ No newline at end of file diff --git a/strategies/cumulative_rsi.py b/strategies/cumulative_rsi.py deleted file mode 100644 index 314ad12..0000000 --- a/strategies/cumulative_rsi.py +++ /dev/null @@ -1,45 +0,0 @@ -import pandas as pd -import numpy as np - -from pandas import DataFrame, Series - -def calculate_moving_average(data: DataFrame, window: int = 200) -> Series: - """ - Calculate the 200-day moving average and return it as a Series without modifying the original DataFrame. - """ - return data['Close'].rolling(window = window).mean() - -def calculate_rsi(data: DataFrame, period: int = 2) -> Series: - """ - Calculate the 2-period RSI and return it as a Series without modifying the original DataFrame. - """ - delta = data['Close'].diff() - gain = np.where(delta > 0, delta, 0) - loss = np.where(delta < 0, -delta, 0) - - alpha = 1 / period - avg_gain = pd.Series(gain).ewm(alpha = alpha, adjust = False).mean() - avg_loss = pd.Series(loss).ewm(alpha = alpha, adjust = False).mean() - - rs = avg_gain / avg_loss - return 100 - (100 / (1 + rs)) - -def calculate_cumulative_rsi(rsi: Series, window: int = 2) -> Series: - """ - Calculate the cumulative RSI over a specified window period and return it as a Series. - """ - return rsi.rolling(window = window).sum() - -def signals(data: DataFrame, rsi_period: int = 2, cumulative_period: int = 2) -> Series: - """ - Generate 'L'ong entry signals based on the Cumulative RSI strategy. - Returns a Series with 'L' for entry signals and 'N' otherwise without modifying the original DataFrame. - - Entry Condition: 2-period cumulative RSI below 35 and above the 200-day moving average. - """ - ma_200 = calculate_moving_average(data) - rsi_2 = calculate_rsi(data, period = rsi_period) - cumulative_rsi_2 = calculate_cumulative_rsi(rsi_2, window = cumulative_period) - - long_condition = (data['Close'] > ma_200) & (cumulative_rsi_2 < 35) - return Series(np.where(long_condition, 'L', 'N'), index = data.index) \ No newline at end of file diff --git a/strategies/declines.py b/strategies/declines.py deleted file mode 100644 index 6cd4b64..0000000 --- a/strategies/declines.py +++ /dev/null @@ -1,22 +0,0 @@ -from pandas import DataFrame, Series -from daily_data import get_daily_data - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the Decline / Advance Ratio strategy. - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - above_200_ma = data['Close'] > data['Close'].rolling(window = 200).mean() - - start_date = data['Date'].min() - end_date = data['Date'].max() - advances = get_daily_data(symbol = 'IINA.Z', start_date = start_date, end_date = end_date) - declines = get_daily_data(symbol = 'IIND.Z', start_date = start_date, end_date = end_date) - - ratio = declines['Close'] / advances['Close'] - ratio_greater_than_2 = ratio >= 2 - - signals = Series('N', index = data.index) - signals[above_200_ma & ratio_greater_than_2] = 'L' - return signals \ No newline at end of file diff --git a/strategies/double_5s.py b/strategies/double_5s.py deleted file mode 100644 index cbaeaec..0000000 --- a/strategies/double_5s.py +++ /dev/null @@ -1,22 +0,0 @@ -import pandas as pd - -def signals(data: pd.DataFrame) -> pd.Series: - """ - Generate trading signals based on the following rules: - 1. SPY is above its 200-day moving average. - 2. Enter a long position if SPY closes at a 5-day low. - - This strategy is based on the Double 7's strategy by Larry Connors. - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - ma_200 = data['Close'].rolling(window = 200).mean() - low_5_day = data['Close'].rolling(window = 5).min() - - above_200_ma = data['Close'] > ma_200 - at_5_day_low = data['Close'] == low_5_day - - signals = pd.Series('N', index = data.index) - signals[above_200_ma & at_5_day_low] = 'L' - - return signals \ No newline at end of file diff --git a/strategies/down_days_in_a_row.py b/strategies/down_days_in_a_row.py deleted file mode 100644 index 566c705..0000000 --- a/strategies/down_days_in_a_row.py +++ /dev/null @@ -1,11 +0,0 @@ -from pandas import DataFrame, Series - -def signals(data: DataFrame) -> Series: - """ - Generate signals for entering a long trade when the market's - close price is lower for 3 consecutive days. - - Returns a Series with 'L' for long signals and 'N' otherwise. - """ - lower_close = data['Close'] < data['Close'].shift(1) - return (lower_close & lower_close.shift(1) & lower_close.shift(2)).apply(lambda x: 'L' if x else 'N') diff --git a/strategies/end_of_month.py b/strategies/end_of_month.py deleted file mode 100644 index 24ddc9b..0000000 --- a/strategies/end_of_month.py +++ /dev/null @@ -1,8 +0,0 @@ -from pandas import DataFrame, Series - -def signals(data: DataFrame) -> Series: - """ - Calculate the End of Month (EOM) signal. - Returns a Series with 'L' for long signals if the date is close to the end of the month and 'N' otherwise. - """ - return data['Date'].apply(lambda x: 'L' if x.day in [23, 24, 25, 26, 27] else 'N') \ No newline at end of file diff --git a/strategies/high_volume_days.py b/strategies/high_volume_days.py deleted file mode 100644 index 46d338b..0000000 --- a/strategies/high_volume_days.py +++ /dev/null @@ -1,17 +0,0 @@ -from pandas import DataFrame, Series - -def signals(data: DataFrame) -> Series: - """ - Generate swing trading signals based on the High Volume Days strategy. - - Returns a Series with 'L' for long signals and 'N' otherwise. - """ - data['200_MA'] = data['Close'].rolling(window = 200).mean() - above_200_ma = data['Close'] > data['200_MA'] - - highest_volume = data['Volume'] == data['Volume'].rolling(window = 5).max() - close_lower_than_open = data['Close'] < data['Open'] - - signal_condition = above_200_ma & highest_volume & close_lower_than_open - signals = signal_condition.apply(lambda condition: 'L' if condition else 'N') - return signals \ No newline at end of file diff --git a/strategies/hilo_index_lows.py b/strategies/hilo_index_lows.py deleted file mode 100644 index f60d9e1..0000000 --- a/strategies/hilo_index_lows.py +++ /dev/null @@ -1,23 +0,0 @@ -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def signals(data: DataFrame) -> Series: - """ - Generate signals based on the HILO Index Lows strategy. - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - above_200_ma = data['Close'] > data['Close'].rolling(window = 200).mean() - - start_date = data['Date'].min() - end_date = data['Date'].max() - new_highs = get_daily_data(symbol = 'FINH.Z', start_date = start_date, end_date = end_date) - new_lows = get_daily_data(symbol = 'FINL.Z', start_date = start_date, end_date = end_date) - - hilo_index = new_highs['Close'] - new_lows['Close'] - hilo_5_day_low = hilo_index == hilo_index.rolling(window = 5).min() - - signals = Series('N', index = data.index) - signals[above_200_ma & hilo_5_day_low] = 'L' - return signals \ No newline at end of file diff --git a/strategies/ibs_rsi.py b/strategies/ibs_rsi.py deleted file mode 100644 index 7873278..0000000 --- a/strategies/ibs_rsi.py +++ /dev/null @@ -1,35 +0,0 @@ -import numpy as np -import pandas as pd - -def calculate_rsi(data: pd.DataFrame, period: int = 21) -> pd.Series: - """ - Calculate the RSI for a given period and return it as a Series. - """ - delta = data['Close'].diff() - gain = np.where(delta > 0, delta, 0) - loss = np.where(delta < 0, -delta, 0) - - alpha = 1 / period - avg_gain = pd.Series(gain).ewm(alpha = alpha, adjust = False).mean() - avg_loss = pd.Series(loss).ewm(alpha = alpha, adjust = False).mean() - - rs = avg_gain / avg_loss - return 100 - (100 / (1 + rs)) - -def calculate_ibs(data: pd.DataFrame) -> pd.Series: - """ - Calculate the IBS and return it as a Series. - """ - return (data['Close'] - data['Low']) / (data['High'] - data['Low']) - -def signals(data: pd.DataFrame) -> pd.Series: - """ - Generate swing trading signals based on the IBS + RSI strategy. - - Returns a Series with 'L' for long signals and 'N' otherwise. - """ - ibs = calculate_ibs(data) - rsi_21 = calculate_rsi(data, period = 21) - - conditions = (ibs < 0.25) & (rsi_21 < 45) - return pd.Series(np.where(conditions, 'L', 'N'), index = data.index) \ No newline at end of file diff --git a/strategies/internal_bar_strength.py b/strategies/internal_bar_strength.py deleted file mode 100644 index 4cfa0c9..0000000 --- a/strategies/internal_bar_strength.py +++ /dev/null @@ -1,9 +0,0 @@ -from pandas import DataFrame, Series - -def signals(data: DataFrame) -> Series: - """ - Calculate the Internal Bar Strength (IBS) signal. - Returns a Series with 'L' for long signals and 'N' otherwise. - """ - ibs_series = (data['Close'] - data['Low']) / (data['High'] - data['Low']) - return ibs_series.apply(lambda ibs: 'L' if ibs < 0.2 else 'N') diff --git a/strategies/internal_bar_strength_band.py b/strategies/internal_bar_strength_band.py deleted file mode 100644 index e946d6b..0000000 --- a/strategies/internal_bar_strength_band.py +++ /dev/null @@ -1,22 +0,0 @@ -import pandas as pd - -def signals(data: pd.DataFrame) -> pd.Series: - """ - Calculate swing trading signals based on Internal Bar Strength Band strategy. - - Returns a Series with 'L' for long signals and 'N' otherwise. - """ - ma_200 = data['Close'].rolling(window = 200).mean() - - rolling_high_minus_low = (data['High'] - data['Low']).rolling(window = 25).mean() - rolling_high = data['High'].rolling(window = 10).max() - lower_band = rolling_high - 2.5 * rolling_high_minus_low - - ibs = (data['Close'] - data['Low']) / (data['High'] - data['Low']) - - signals = ( - (data['Close'] > ma_200) & - (data['Close'] < lower_band) & - (ibs < 0.3) - ).apply(lambda condition: 'L' if condition else 'N') - return signals \ No newline at end of file diff --git a/strategies/large_moves_down.py b/strategies/large_moves_down.py deleted file mode 100644 index b378a58..0000000 --- a/strategies/large_moves_down.py +++ /dev/null @@ -1,10 +0,0 @@ -from pandas import DataFrame, Series - -def signals(data: DataFrame) -> Series: - """ - Generate swing trading signals based the Large Moves (Down) strategy. - - Returns a Series with 'L' for long signals and 'N' otherwise. - """ - percent_change = (data['Open'] - data['Close']) / data['Open'] - return percent_change.apply(lambda change: 'L' if change >= 0.01 else 'N') \ No newline at end of file diff --git a/strategies/lower_lows.py b/strategies/lower_lows.py deleted file mode 100644 index 75ff5cd..0000000 --- a/strategies/lower_lows.py +++ /dev/null @@ -1,11 +0,0 @@ -from pandas import DataFrame, Series - -def signals(data: DataFrame) -> Series: - """ - Generate signals for entering a long trade when the market makes - a lower low for 2 consecutive days. - - Returns a Series with 'L' for long signals and 'N' otherwise. - """ - lower_low = data['Low'].shift(1) > data['Low'] - return (lower_low & lower_low.shift(1)).apply(lambda x: 'L' if x else 'N') \ No newline at end of file diff --git a/strategies/put_call_ratio_highs.py b/strategies/put_call_ratio_highs.py deleted file mode 100644 index ece25a4..0000000 --- a/strategies/put_call_ratio_highs.py +++ /dev/null @@ -1,27 +0,0 @@ -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def signals(data: DataFrame) -> Series: - """ - Generate signals based on the Put / Call Ratio Highs strategy. - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - above_200_ma = data['Close'] > data['Close'].rolling(window = 200).mean() - - start_date = data['Date'].min() - end_date = data['Date'].max() - put_volume = get_daily_data(symbol = 'VPOT.Z', start_date = start_date, end_date = end_date) - call_volume = get_daily_data(symbol = 'VCOT.Z', start_date = start_date, end_date = end_date) - - # The put and call volume data contains extraneous data for holidays when the market is closed. - put_volume = put_volume[put_volume['Date'].isin(data['Date'])].reset_index(drop = True) - call_volume = call_volume[call_volume['Date'].isin(data['Date'])].reset_index(drop = True) - - put_call_ratio = put_volume['Close'] / call_volume['Close'] - put_call_high_5_day = put_call_ratio == put_call_ratio.rolling(window = 5).max() - - signals = Series('N', index = data.index) - signals[above_200_ma & put_call_high_5_day] = 'L' - return signals \ No newline at end of file diff --git a/strategies/rsi_power_zones.py b/strategies/rsi_power_zones.py deleted file mode 100644 index 06d04b1..0000000 --- a/strategies/rsi_power_zones.py +++ /dev/null @@ -1,38 +0,0 @@ -import numpy as np - -from pandas import DataFrame, Series - -def calculate_moving_average(data: DataFrame, window: int = 200) -> Series: - """ - Calculate the moving average and return it as a Series. - """ - return data['Close'].rolling(window=window).mean() - -def calculate_rsi(data: DataFrame, period: int = 4) -> Series: - """ - Calculate the RSI and return it as a Series. - """ - delta = data['Close'].diff() - gain = np.where(delta > 0, delta, 0) - loss = np.where(delta < 0, -delta, 0) - - alpha = 1 / period - avg_gain = Series(gain).ewm(alpha=alpha, adjust=False).mean() - avg_loss = Series(loss).ewm(alpha=alpha, adjust=False).mean() - - rs = avg_gain / avg_loss - return 100 - (100 / (1 + rs)) - -def signals(data: DataFrame) -> Series: - """ - Calculate signals for the RSI PowerZones strategy. - Returns a Series with 'L' for long signals and 'N' otherwise. - """ - ma_200 = calculate_moving_average(data, window = 200) - rsi_4 = calculate_rsi(data, period = 4) - - above_ma_200 = data['Close'] > ma_200 - rsi_below_30 = rsi_4 < 30 - - conditions = above_ma_200 & rsi_below_30 - return Series(np.where(conditions, 'L', 'N'), index = data.index) \ No newline at end of file diff --git a/strategies/short_term_lows.py b/strategies/short_term_lows.py deleted file mode 100644 index cad0b6f..0000000 --- a/strategies/short_term_lows.py +++ /dev/null @@ -1,10 +0,0 @@ -from pandas import DataFrame, Series - -def signals(data: DataFrame) -> Series: - """ - Generate signals for entering a long trade when the market makes a 10-day low. - - Returns a series with 'L' for long signals and 'N' otherwise. - """ - ten_day_low = data['Low'] == data['Low'].rolling(window = 10, min_periods = 10).min() - return ten_day_low.apply(lambda x: 'L' if x else 'N') \ No newline at end of file diff --git a/strategies/tps.py b/strategies/tps.py deleted file mode 100644 index 1123f96..0000000 --- a/strategies/tps.py +++ /dev/null @@ -1,40 +0,0 @@ -import numpy as np - -from pandas import DataFrame, Series - -def calculate_moving_average(data: DataFrame, window: int = 200) -> Series: - """ - Calculate the 200-period moving average and return it as a Series without modifying the original DataFrame. - """ - return data['Close'].rolling(window = window).mean() - -def calculate_rsi(data: DataFrame, period: int = 2) -> Series: - """ - Calculate the 2-period RSI and return it as a Series without modifying the original DataFrame. - """ - delta = data['Close'].diff() - gain = np.where(delta > 0, delta, 0) - loss = np.where(delta < 0, -delta, 0) - - alpha = 1 / period - avg_gain = Series(gain).ewm(alpha = alpha, adjust = False).mean() - avg_loss = Series(loss).ewm(alpha = alpha, adjust = False).mean() - - rs = avg_gain / avg_loss - return 100 - (100 / (1 + rs)) - -def signals(data: DataFrame) -> Series: - """ - Calculate signals based on the Time, Price, Scale-in (TPS) strategy. - Returns a Series with 'Long' for signals and 'None' otherwise, without modifying the original DataFrame. - """ - ma_200 = calculate_moving_average(data) - rsi_2 = calculate_rsi(data) - - above_ma_200 = data['Close'] > ma_200 - - rsi_below_25 = (rsi_2 < 25) - rsi_below_25_for_two_days = rsi_below_25 & rsi_below_25.shift(1, fill_value = False) - - conditions = above_ma_200 & rsi_below_25_for_two_days - return Series(np.where(conditions, 'L', 'N'), index = data.index) \ No newline at end of file diff --git a/strategies/trin.py b/strategies/trin.py deleted file mode 100644 index 25a6823..0000000 --- a/strategies/trin.py +++ /dev/null @@ -1,46 +0,0 @@ -import numpy as np - -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def calculate_rsi(data: DataFrame, period: int = 2) -> Series: - """ - Calculate the RSI and return it as a Series without modifying the original DataFrame. - """ - delta = data['Close'].diff() - gain = np.where(delta > 0, delta, 0) - loss = np.where(delta < 0, -delta, 0) - - alpha = 1 / period - avg_gain = Series(gain).ewm(alpha = alpha, adjust = False).mean() - avg_loss = Series(loss).ewm(alpha = alpha, adjust = False).mean() - - rs = avg_gain / avg_loss - return 100 - (100 / (1 + rs)) - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the TRIN strategy with the following rules: - 1. SPY is above its 200-day moving average - 2. 2-period RSI is below 50 - 3. TRIN closes above 1 - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - ma_200 = data['Close'].rolling(window = 200).mean() - - rsi_2 = calculate_rsi(data, period = 2) - - start_date = data['Date'].min() - end_date = data['Date'].max() - trin_data = get_daily_data(symbol = 'RINT.Z', start_date = start_date, end_date = end_date) - - trin_above_1 = trin_data['Close'] > 1 - - above_200_ma = data['Close'] > ma_200 - rsi_below_50 = rsi_2 < 50 - - signals = Series('N', index = data.index) - signals[above_200_ma & rsi_below_50 & trin_above_1] = 'L' - return signals \ No newline at end of file diff --git a/strategies/trin_thrusts.py b/strategies/trin_thrusts.py deleted file mode 100644 index b0178ea..0000000 --- a/strategies/trin_thrusts.py +++ /dev/null @@ -1,20 +0,0 @@ -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the TRIN Thrusts strategy. - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - start_date = data['Date'].min() - end_date = data['Date'].max() - trin_data = get_daily_data(symbol = 'RINT.Z', start_date = start_date, end_date = end_date) - - trin_change = trin_data['Close'].pct_change() - trin_30_below = trin_change <= -0.4 - - signals = Series('N', index = data.index) - signals[trin_30_below] = 'L' - return signals \ No newline at end of file diff --git a/strategies/turnaround.py b/strategies/turnaround.py deleted file mode 100644 index 5e18f75..0000000 --- a/strategies/turnaround.py +++ /dev/null @@ -1,16 +0,0 @@ -from pandas import DataFrame, Series, to_datetime - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the day of the week and downward close conditions. - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - date_series = to_datetime(data['Date'], errors = 'coerce') - monday_or_tuesday = date_series.dt.dayofweek.isin([0, 1]) - lower_past_two_days = (data['Close'] < data['Close'].shift(1)) & (data['Close'].shift(1) < data['Close'].shift(2)) - - signals = Series('N', index=data.index) - signals[monday_or_tuesday & lower_past_two_days] = 'L' - - return signals \ No newline at end of file diff --git a/strategies/two_period_rsi.py b/strategies/two_period_rsi.py deleted file mode 100644 index 804bd1f..0000000 --- a/strategies/two_period_rsi.py +++ /dev/null @@ -1,35 +0,0 @@ -import numpy as np - -from pandas import DataFrame, Series - -def calculate_moving_average(data: DataFrame, window: int = 200) -> Series: - """ - Calculate the 200-period moving average and return it as a Series without modifying the original DataFrame. - """ - return data['Close'].rolling(window = window).mean() - -def calculate_rsi(data: DataFrame, period: int = 2) -> Series: - """ - Calculate the 2-period RSI and return it as a Series without modifying the original DataFrame. - """ - delta = data['Close'].diff() - gain = np.where(delta > 0, delta, 0) - loss = np.where(delta < 0, -delta, 0) - - alpha = 1 / period - avg_gain = Series(gain).ewm(alpha = alpha, adjust = False).mean() - avg_loss = Series(loss).ewm(alpha = alpha, adjust = False).mean() - - rs = avg_gain / avg_loss - return 100 - (100 / (1 + rs)) - -def signals(data: DataFrame) -> Series: - """ - Calculate signals based on the 200-period MA and 2-period RSI. - Returns a Series with 'Long' for signals and 'None' otherwise, without modifying the original DataFrame. - """ - ma_200 = calculate_moving_average(data) - rsi_2 = calculate_rsi(data) - - conditions = (data['Close'] > ma_200) & (rsi_2 < 15) - return Series(np.where(conditions, 'L', 'N'), index = data.index) \ No newline at end of file diff --git a/strategies/vix_above_moving_average.py b/strategies/vix_above_moving_average.py deleted file mode 100644 index 52a7972..0000000 --- a/strategies/vix_above_moving_average.py +++ /dev/null @@ -1,23 +0,0 @@ -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the VIX Above Moving Average strategy. - - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - ma_200 = data['Close'].rolling(window = 200).mean() - above_200_ma = data['Close'] > ma_200 - - start_date = data['Date'].min() - end_date = data['Date'].max() - vix_data = get_daily_data(symbol='VIX.XO', start_date = start_date, end_date = end_date) - - vix_ma_10 = vix_data['Close'].rolling(window = 10).mean() - vix_close_10_percent_above_ma = vix_data['Close'] >= (1.1 * vix_ma_10) - - signals = Series('N', index = data.index) - signals[above_200_ma & vix_close_10_percent_above_ma] = 'L' - return signals \ No newline at end of file diff --git a/strategies/vix_reversal_1.py b/strategies/vix_reversal_1.py deleted file mode 100644 index 0d9d3c9..0000000 --- a/strategies/vix_reversal_1.py +++ /dev/null @@ -1,23 +0,0 @@ -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the VIX 15-day high strategy. - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - ma_200 = data['Close'].rolling(window = 200).mean() - above_200_ma = data['Close'] > ma_200 - - start_date = data['Date'].min() - end_date = data['Date'].max() - vix_data = get_daily_data(symbol='VIX.XO', start_date=start_date, end_date=end_date) - - vix_15_day_high = vix_data['High'] == vix_data['High'].rolling(window = 15).max() - - vix_close_below_open = vix_data['Close'] < vix_data['Open'] - - signals = Series('N', index = data.index) - signals[above_200_ma & vix_15_day_high & vix_close_below_open] = 'L' - return signals \ No newline at end of file diff --git a/strategies/vix_reversal_2.py b/strategies/vix_reversal_2.py deleted file mode 100644 index 283d5f5..0000000 --- a/strategies/vix_reversal_2.py +++ /dev/null @@ -1,38 +0,0 @@ -import numpy as np - -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def calculate_rsi(data: DataFrame, period: int = 5) -> Series: - """ - Calculate the RSI and return it as a Series without modifying the original DataFrame. - """ - delta = data['Close'].diff() - gain = np.where(delta > 0, delta, 0) - loss = np.where(delta < 0, -delta, 0) - - alpha = 1 / period - avg_gain = Series(gain).ewm(alpha = alpha, adjust = False).mean() - avg_loss = Series(loss).ewm(alpha = alpha, adjust = False).mean() - - rs = avg_gain / avg_loss - return 100 - (100 / (1 + rs)) - -def signals(data: DataFrame) -> Series: - """ - Generate swing trading signals based on the Connors VIX Reversal 2 strategy. - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - start_date = data['Date'].min() - end_date = data['Date'].max() - vix_data = get_daily_data(symbol = 'VIX.XO', start_date = start_date, end_date = end_date) - - vix_rsi_5 = calculate_rsi(vix_data, period = 5) - - vix_rsi_above_70 = vix_rsi_5.shift(1) > 70 - vix_close_below_prev_close = vix_data['Close'] < vix_data['Close'].shift(1) - - signals = Series('N', index = data.index) - signals[vix_rsi_above_70 & vix_close_below_prev_close] = 'L' - return signals \ No newline at end of file diff --git a/strategies/vix_reversal_3.py b/strategies/vix_reversal_3.py deleted file mode 100644 index c304452..0000000 --- a/strategies/vix_reversal_3.py +++ /dev/null @@ -1,21 +0,0 @@ -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the Connors VIX Reversal 3 strategy. - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - start_date = data['Date'].min() - end_date = data['Date'].max() - vix_data = get_daily_data(symbol = 'VIX.XO', start_date = start_date, end_date = end_date) - - vix_ma_50 = vix_data['Close'].rolling(window = 50).mean() - - vix_low_above_50_ma = vix_data['Low'] > vix_ma_50 - vix_close_10_percent_above_ma = vix_data['Close'] >= (1.1 * vix_ma_50) - - signals = Series('N', index = data.index) - signals[vix_low_above_50_ma & vix_close_10_percent_above_ma] = 'L' - return signals \ No newline at end of file diff --git a/strategies/vix_rsi.py b/strategies/vix_rsi.py deleted file mode 100644 index ca37e51..0000000 --- a/strategies/vix_rsi.py +++ /dev/null @@ -1,44 +0,0 @@ -import numpy as np - -from pandas import DataFrame, Series - -from daily_data import get_daily_data - -def calculate_rsi(data: DataFrame, period: int = 2) -> Series: - """ - Calculate the RSI and return it as a Series without modifying the original DataFrame. - """ - delta = data['Close'].diff() - gain = np.where(delta > 0, delta, 0) - loss = np.where(delta < 0, -delta, 0) - - alpha = 1 / period - avg_gain = Series(gain).ewm(alpha = alpha, adjust = False).mean() - avg_loss = Series(loss).ewm(alpha = alpha, adjust = False).mean() - - rs = avg_gain / avg_loss - return 100 - (100 / (1 + rs)) - -def signals(data: DataFrame) -> Series: - """ - Generate long signals based on the VIX RSI strategy. - Returns a Series with 'L' for long signals and 'N' for no signal. - """ - ma_200 = data['Close'].rolling(window = 200).mean() - rsi_2 = calculate_rsi(data, period = 2) - - start_date = data['Date'].min() - end_date = data['Date'].max() - vix_data = get_daily_data(symbol = 'VIX.XO', start_date = start_date, end_date = end_date) - - vix_rsi_2 = calculate_rsi(vix_data, period = 2) - - above_200_ma = data['Close'] > ma_200 - vix_rsi_above_90 = vix_rsi_2 > 90 - vix_open_greater_than_prev_close = vix_data['Open'] > vix_data['Close'].shift(1) - rsi_below_30 = rsi_2 < 30 - - signals = Series('N', index = data.index) - signals[above_200_ma & vix_rsi_above_90 & vix_open_greater_than_prev_close & rsi_below_30] = 'L' - - return signals