diff --git a/strategy/generator/bootstrap/_trend_follow.py b/strategy/generator/bootstrap/_trend_follow.py index 41706337..6ceea7f5 100644 --- a/strategy/generator/bootstrap/_trend_follow.py +++ b/strategy/generator/bootstrap/_trend_follow.py @@ -20,7 +20,8 @@ from strategy.generator.confirm.dso import DsoConfirm from strategy.generator.confirm.eom import EomConfirm from strategy.generator.confirm.roc import RocConfirm -from strategy.generator.confirm.rsi import RsiConfirm +from strategy.generator.confirm.rsi_neutrality import RsiNeutralityConfirm +from strategy.generator.confirm.rsi_signalline import RsiSignalLineConfirm from strategy.generator.confirm.stc import StcConfirm from strategy.generator.exit.ast import AstExit from strategy.generator.exit.cci import CciExit @@ -44,9 +45,15 @@ from strategy.generator.signal.ma.ma3_cross import Ma3CrossSignal from strategy.generator.signal.ma.ma_testing_ground import MaTestingGroundSignal from strategy.generator.signal.ma.vwap_cross import VwapCrossSignal -from strategy.generator.signal.neutrality.dso_neutrality_cross import DsoNeutralityCrossSignal -from strategy.generator.signal.neutrality.rsi_neutrality_cross import RsiNautralityCrossSignal -from strategy.generator.signal.neutrality.rsi_neutrality_pullback import RsiNautralityPullbackSignal +from strategy.generator.signal.neutrality.dso_neutrality_cross import ( + DsoNeutralityCrossSignal, +) +from strategy.generator.signal.neutrality.rsi_neutrality_cross import ( + RsiNautralityCrossSignal, +) +from strategy.generator.signal.neutrality.rsi_neutrality_pullback import ( + RsiNautralityPullbackSignal, +) from strategy.generator.signal.neutrality.rsi_neutrality_rejection import ( RsiNautralityRejectionSignal, ) @@ -63,7 +70,9 @@ from strategy.generator.signal.signalline.dso_signalline import DsoSignalLineSignal from strategy.generator.signal.signalline.kst_signalline import KstSignalLineSignal from strategy.generator.signal.signalline.macd_signalline import MacdSignalLineSignal -from strategy.generator.signal.signalline.qstick_signalline import QstickSignalLineSignal +from strategy.generator.signal.signalline.qstick_signalline import ( + QstickSignalLineSignal, +) from strategy.generator.signal.signalline.rsi_signalline import RsiSignalLineSignal from strategy.generator.signal.signalline.stoch_signalline import StochSignalLineSignal from strategy.generator.signal.signalline.trix_signalline import TrixSignalLineSignal @@ -167,7 +176,8 @@ def _generate_strategy(self): DpoConfirm(), EomConfirm(), RocConfirm(), - RsiConfirm(), + RsiSignalLineConfirm(), + RsiNeutralityConfirm(), StcConfirm(), DsoConfirm(), CciConfirm(), diff --git a/strategy/generator/confirm/base.py b/strategy/generator/confirm/base.py index a652e556..c94e43d1 100644 --- a/strategy/generator/confirm/base.py +++ b/strategy/generator/confirm/base.py @@ -11,7 +11,8 @@ class ConfirmType(Enum): Cci = "Cci" Eom = "Eom" Roc = "Roc" - Rsi = "Rsi" + RsiSignalLine = "RsiSignalLine" + RsiNeutrality = "RsiNeutrality" Stc = "Stc" def __str__(self): diff --git a/strategy/generator/confirm/rsi_neutrality.py b/strategy/generator/confirm/rsi_neutrality.py new file mode 100644 index 00000000..fb1644b1 --- /dev/null +++ b/strategy/generator/confirm/rsi_neutrality.py @@ -0,0 +1,14 @@ +from dataclasses import dataclass + +from core.models.parameter import Parameter, RandomParameter, StaticParameter +from core.models.smooth import Smooth + +from .base import Confirm, ConfirmType + + +@dataclass(frozen=True) +class RsiNeutralityConfirm(Confirm): + type: Confirm = ConfirmType.RsiNeutrality + smooth_type: Parameter = StaticParameter(Smooth.SMMA) + period: Parameter = StaticParameter(14.0) + threshold: Parameter = RandomParameter(0.0, 3.0, 1.0) diff --git a/strategy/generator/confirm/rsi.py b/strategy/generator/confirm/rsi_signalline.py similarity index 85% rename from strategy/generator/confirm/rsi.py rename to strategy/generator/confirm/rsi_signalline.py index ad6b83da..e40f18a7 100644 --- a/strategy/generator/confirm/rsi.py +++ b/strategy/generator/confirm/rsi_signalline.py @@ -7,8 +7,8 @@ @dataclass(frozen=True) -class RsiConfirm(Confirm): - type: Confirm = ConfirmType.Rsi +class RsiSignalLineConfirm(Confirm): + type: Confirm = ConfirmType.RsiSignalLine smooth_type: Parameter = StaticParameter(Smooth.SMMA) period: Parameter = StaticParameter(14.0) smooth_signal: Parameter = StaticParameter(Smooth.WMA) diff --git a/ta_lib/strategies/confirm/src/lib.rs b/ta_lib/strategies/confirm/src/lib.rs index 4e30264a..9720067d 100644 --- a/ta_lib/strategies/confirm/src/lib.rs +++ b/ta_lib/strategies/confirm/src/lib.rs @@ -4,7 +4,8 @@ mod dso; mod dumb; mod eom; mod roc; -mod rsi; +mod rsi_neutrality; +mod rsi_signalline; mod stc; pub use cci::CciConfirm; @@ -13,5 +14,6 @@ pub use dso::DsoConfirm; pub use dumb::DumbConfirm; pub use eom::EomConfirm; pub use roc::RocConfirm; -pub use rsi::RsiConfirm; +pub use rsi_neutrality::RsiNeutralityConfirm; +pub use rsi_signalline::RsiSignalLineConfirm; pub use stc::StcConfirm; diff --git a/ta_lib/strategies/confirm/src/rsi_neutrality.rs b/ta_lib/strategies/confirm/src/rsi_neutrality.rs new file mode 100644 index 00000000..7829c51e --- /dev/null +++ b/ta_lib/strategies/confirm/src/rsi_neutrality.rs @@ -0,0 +1,54 @@ +use base::prelude::*; +use core::prelude::*; +use momentum::rsi; + +const RSI_UPPER_BARRIER: f32 = 75.0; +const RSI_LOWER_BARRIER: f32 = 25.0; + +pub struct RsiNeutralityConfirm { + smooth_type: Smooth, + period: usize, + threshold: f32, +} + +impl RsiNeutralityConfirm { + pub fn new(smooth_type: Smooth, period: f32, threshold: f32) -> Self { + Self { + smooth_type, + period: period as usize, + threshold, + } + } +} + +impl Confirm for RsiNeutralityConfirm { + fn lookback(&self) -> usize { + self.period + } + + fn validate(&self, data: &OHLCVSeries) -> (Series, Series) { + let rsi = rsi(&data.close, self.smooth_type, self.period); + + let lower_barrier = RSI_LOWER_BARRIER + self.threshold; + let upper_barrier = RSI_UPPER_BARRIER - self.threshold; + let lower_neutrality = NEUTRALITY_LINE - self.threshold; + let upper_neutrality = NEUTRALITY_LINE + self.threshold; + + let prev_rsi = rsi.shift(1); + let back_2_rsi = rsi.shift(2); + let back_3_rsi = rsi.shift(3); + + ( + rsi.sgt(&NEUTRALITY_LINE) + & rsi.slt(&upper_barrier) + & prev_rsi.sgt(&lower_neutrality) + & back_2_rsi.sgt(&lower_neutrality) + & back_3_rsi.sgt(&lower_neutrality), + rsi.slt(&NEUTRALITY_LINE) + & rsi.sgt(&lower_barrier) + & prev_rsi.slt(&upper_neutrality) + & back_2_rsi.slt(&upper_neutrality) + & back_3_rsi.slt(&upper_neutrality), + ) + } +} diff --git a/ta_lib/strategies/confirm/src/rsi.rs b/ta_lib/strategies/confirm/src/rsi_signalline.rs similarity index 92% rename from ta_lib/strategies/confirm/src/rsi.rs rename to ta_lib/strategies/confirm/src/rsi_signalline.rs index 95cca08d..0935c994 100644 --- a/ta_lib/strategies/confirm/src/rsi.rs +++ b/ta_lib/strategies/confirm/src/rsi_signalline.rs @@ -5,7 +5,7 @@ use momentum::rsi; const RSI_UPPER_BARRIER: f32 = 75.; const RSI_LOWER_BARRIER: f32 = 35.; -pub struct RsiConfirm { +pub struct RsiSignalLineConfirm { smooth_type: Smooth, rsi_period: usize, smooth_signal: Smooth, @@ -13,7 +13,7 @@ pub struct RsiConfirm { threshold: f32, } -impl RsiConfirm { +impl RsiSignalLineConfirm { pub fn new( smooth_type: Smooth, rsi_period: f32, @@ -31,7 +31,7 @@ impl RsiConfirm { } } -impl Confirm for RsiConfirm { +impl Confirm for RsiSignalLineConfirm { fn lookback(&self) -> usize { std::cmp::max(self.rsi_period, self.smooth_period) } diff --git a/ta_lib/strategies/signal/src/rsi_supertrend.rs b/ta_lib/strategies/signal/src/rsi_supertrend.rs deleted file mode 100644 index 0e710fe3..00000000 --- a/ta_lib/strategies/signal/src/rsi_supertrend.rs +++ /dev/null @@ -1,82 +0,0 @@ -use base::prelude::*; -use core::prelude::*; -use momentum::rsi; -use trend::supertrend; - -const RSI_UPPER_BARRIER: f32 = 75.0; -const RSI_LOWER_BARRIER: f32 = 25.0; - -pub struct RSISupertrendSignal { - smooth_type: Smooth, - rsi_period: usize, - threshold: f32, - atr_period: usize, - factor: f32, -} - -impl RSISupertrendSignal { - pub fn new( - smooth_type: Smooth, - rsi_period: f32, - threshold: f32, - atr_period: f32, - factor: f32, - ) -> Self { - Self { - smooth_type, - rsi_period: rsi_period as usize, - threshold, - atr_period: atr_period as usize, - factor, - } - } -} - -impl Signal for RSISupertrendSignal { - fn lookback(&self) -> usize { - std::cmp::max(self.rsi_period, self.atr_period) - } - - fn generate(&self, data: &OHLCVSeries) -> (Series, Series) { - let rsi = rsi(&data.close, self.smooth_type, self.rsi_period); - let (direction, _) = supertrend( - &data.hl2(), - &data.close, - &data.atr(self.atr_period, Smooth::SMMA), - self.factor, - ); - let lower_barrier = RSI_LOWER_BARRIER + self.threshold; - let upper_barrier = RSI_UPPER_BARRIER - self.threshold; - let lower_neutrality = NEUTRALITY_LINE - self.threshold; - let upper_neutrality = NEUTRALITY_LINE + self.threshold; - - let prev_direction = direction.shift(1); - let back_2_direction = direction.shift(2); - let back_3_direction = direction.shift(3); - - let prev_rsi = rsi.shift(1); - let back_2_rsi = rsi.shift(2); - let back_3_rsi = rsi.shift(3); - - ( - direction.seq(&ONE) - & prev_direction.seq(&ONE) - & back_2_direction.seq(&ONE) - & back_3_direction.seq(&ONE) - & rsi.sgt(&NEUTRALITY_LINE) - & rsi.slt(&upper_barrier) - & prev_rsi.sgt(&lower_neutrality) - & back_2_rsi.sgt(&lower_neutrality) - & back_3_rsi.sgt(&lower_neutrality), - direction.seq(&MINUS_ONE) - & prev_direction.seq(&MINUS_ONE) - & back_2_direction.seq(&MINUS_ONE) - & back_3_direction.seq(&MINUS_ONE) - & rsi.slt(&NEUTRALITY_LINE) - & rsi.sgt(&lower_barrier) - & prev_rsi.slt(&upper_neutrality) - & back_2_rsi.slt(&upper_neutrality) - & back_3_rsi.slt(&upper_neutrality), - ) - } -} diff --git a/ta_lib/strategies/trend_follow/src/config/confirm_config.rs b/ta_lib/strategies/trend_follow/src/config/confirm_config.rs index 40e72604..691497cc 100644 --- a/ta_lib/strategies/trend_follow/src/config/confirm_config.rs +++ b/ta_lib/strategies/trend_follow/src/config/confirm_config.rs @@ -20,7 +20,12 @@ pub enum ConfirmConfig { Dumb { period: f32, }, - Rsi { + RsiNeutrality { + smooth_type: f32, + period: f32, + threshold: f32, + }, + RsiSignalLine { smooth_type: f32, period: f32, smooth_signal: f32, diff --git a/ta_lib/strategies/trend_follow/src/mapper/confirm_mapper.rs b/ta_lib/strategies/trend_follow/src/mapper/confirm_mapper.rs index 99fe548d..bbfcec0b 100644 --- a/ta_lib/strategies/trend_follow/src/mapper/confirm_mapper.rs +++ b/ta_lib/strategies/trend_follow/src/mapper/confirm_mapper.rs @@ -43,19 +43,28 @@ pub fn map_to_confirm(config: ConfirmConfig) -> Box { divisor, )), ConfirmConfig::Dumb { period } => Box::new(DumbConfirm::new(period)), - ConfirmConfig::Rsi { + ConfirmConfig::RsiSignalLine { smooth_type, period, smooth_signal, smooth_period, threshold, - } => Box::new(RsiConfirm::new( + } => Box::new(RsiSignalLineConfirm::new( smooth_deserialize(smooth_type as usize), period, smooth_deserialize(smooth_signal as usize), smooth_period, threshold, )), + ConfirmConfig::RsiNeutrality { + smooth_type, + period, + threshold, + } => Box::new(RsiNeutralityConfirm::new( + smooth_deserialize(smooth_type as usize), + period, + threshold, + )), ConfirmConfig::Roc { period } => Box::new(RocConfirm::new(period)), ConfirmConfig::Stc { smooth_type,