Untitled
unknown
plain_text
13 days ago
19 kB
5
Indexable
module Analyzers class PatternAnalysis < Base BULLISH_PATTERNS = { 'bullish_belt_hold' => { weight: 1.2, volume_condition: :high, confirmation: :ema_cross }, 'three_white_soldiers' => { weight: 1.7, volume_condition: :sustained, confirmation: :volume_increase }, 'volume_breakout' => { weight: 1.5, volume_condition: :extreme, confirmation: :resistance_break }, 'spring' => { weight: 1.3, volume_condition: :high, confirmation: :follow_through }, 'morning_star' => { weight: 1.6, volume_condition: :breakout, confirmation: :third_candle_confirmation }, 'piercing_line' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_confirmation }, 'marubozu_bullish' => { weight: 1.3, volume_condition: :high, confirmation: :continuation }, 'double_bottom' => { weight: 1.4, volume_condition: :breakout, confirmation: :neckline_break }, 'bullish_harami' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_confirmation }, 'inverted_hammer' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_bullish }, 'rsi_bullish_divergence' => { weight: 1.3, volume_condition: :none, confirmation: :rsi_oversold }, 'hammer' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_bullish }, 'bullish_engulfing' => { weight: 1.5, volume_condition: :high, confirmation: :next_candle_confirmation }, 'unique_three_river_bottom' => { weight: 1.4, volume_condition: :high, confirmation: :next_candle_confirmation }, 'breakaway_bullish' => { weight: 1.5, volume_condition: :breakout, confirmation: :gap_hold }, 'bullish_kicker' => { weight: 1.5, volume_condition: :extreme, confirmation: :gap_hold }, 'bullish_separating_lines' => { weight: 1.2, volume_condition: :normal, confirmation: :trend_confirmation }, 'abandoned_baby_bullish' => { weight: 1.4, volume_condition: :high, confirmation: :gap_fill }, 'tweezer_bottom' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_bullish }, 'rounding_bottom' => { weight: 1.5, volume_condition: :sustained, confirmation: :breakout_high_volume }, 'mat_hold_bullish' => { weight: 1.4, volume_condition: :sustained, confirmation: :pullback_continuation }, 'thrusting_line' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_confirmation }, 'dragonfly_doji' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_bullish }, 'long_legged_doji_bullish' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_confirmation }, 'meeting_lines_bullish' => { weight: 1.2, volume_condition: :high, confirmation: :trend_confirmation }, 'stick_sandwich' => { weight: 1.3, volume_condition: :high, confirmation: :next_candle_confirmation }, 'tristar_bullish' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_bullish }, 'symmetrical_triangle_bullish' => { weight: 1.4, volume_condition: :breakout, confirmation: :breakout_direction }, 'triple_bottom' => { weight: 1.6, volume_condition: :breakout, confirmation: :neckline_break }, 'doji_star_bullish' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_bullish }, 'cup_with_handle' => { weight: 1.6, volume_condition: :breakout, confirmation: :handle_breakout }, 'flag_bullish' => { weight: 1.3, volume_condition: :breakout, confirmation: :flag_pole_ratio }, 'pennant_bullish' => { weight: 1.3, volume_condition: :breakout, confirmation: :volume_contraction }, 'ascending_triangle' => { weight: 1.5, volume_condition: :breakout, confirmation: :resistance_break }, 'descending_triangle_bullish' => { weight: 1.4, volume_condition: :breakout, confirmation: :support_hold }, 'belt_hold_bullish' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_confirmation }, 'rising_three_methods' => { weight: 1.3, volume_condition: :sustained, confirmation: :continuation }, 'three_line_strike_bullish' => { weight: 1.3, volume_condition: :breakout, confirmation: :volume_spike }, 'falling_wedge_bullish' => { weight: 1.4, volume_condition: :breakout, confirmation: :wedge_breakout }, 'macd_crossover' => { weight: 1.2, volume_condition: :normal, confirmation: :macd_line_cross } }.freeze BEARISH_PATTERNS = { 'bearish_belt_hold' => { weight: 1.2, volume_condition: :high, confirmation: :ema_cross }, 'head_and_shoulders' => { weight: 1.6, volume_condition: :breakout, confirmation: :neckline_break }, 'volume_spike' => { weight: 1.3, volume_condition: :extreme, confirmation: :price_rejection }, 'bearish_engulfing' => { weight: 1.5, volume_condition: :high, confirmation: :next_candle_confirmation }, 'dark_cloud_cover' => { weight: 1.4, volume_condition: :high, confirmation: :next_candle_confirmation }, 'evening_star' => { weight: 1.6, volume_condition: :breakout, confirmation: :third_candle_confirmation }, 'upthrust' => { weight: 1.4, volume_condition: :high, confirmation: :volume_confirmation }, 'low_volume_pullback' => { weight: 1.1, volume_condition: :low, confirmation: :continuation }, 'abandoned_baby_bearish' => { weight: 1.4, volume_condition: :high, confirmation: :gap_fill }, 'three_black_crows' => { weight: 1.7, volume_condition: :sustained, confirmation: :volume_increase }, 'marubozu_bearish' => { weight: 1.3, volume_condition: :high, confirmation: :continuation }, 'rounding_top' => { weight: 1.5, volume_condition: :sustained, confirmation: :breakout_high_volume }, 'bearish_harami' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_confirmation }, 'tweezer_top' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_bearish }, 'bearish_kicker' => { weight: 1.5, volume_condition: :extreme, confirmation: :gap_hold }, 'bearish_separating_lines' => { weight: 1.2, volume_condition: :normal, confirmation: :trend_confirmation }, 'gravestone_doji' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_bearish }, 'long_legged_doji_bearish' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_confirmation }, 'meeting_lines_bearish' => { weight: 1.2, volume_condition: :high, confirmation: :trend_confirmation }, 'two_crows' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_confirmation }, 'upside_gap_two_crows' => { weight: 1.3, volume_condition: :high, confirmation: :gap_fill }, 'tristar_bearish' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_bearish }, 'symmetrical_triangle_bearish' => { weight: 1.4, volume_condition: :breakout, confirmation: :breakout_direction }, 'head_and_shoulders_top' => { weight: 1.6, volume_condition: :breakout, confirmation: :neckline_break }, 'triple_top' => { weight: 1.6, volume_condition: :breakout, confirmation: :neckline_break }, 'doji_star_bearish' => { weight: 1.1, volume_condition: :normal, confirmation: :next_candle_bearish }, 'breakaway_bearish' => { weight: 1.5, volume_condition: :breakout, confirmation: :gap_hold }, 'mat_hold_bearish' => { weight: 1.4, volume_condition: :sustained, confirmation: :pullback_continuation }, 'rising_wedge_bearish' => { weight: 1.4, volume_condition: :breakout, confirmation: :wedge_breakout }, 'flag_bearish' => { weight: 1.3, volume_condition: :breakout, confirmation: :flag_pole_ratio }, 'pennant_bearish' => { weight: 1.3, volume_condition: :breakout, confirmation: :volume_contraction }, 'ascending_triangle_bearish' => { weight: 1.5, volume_condition: :breakout, confirmation: :support_break }, 'descending_triangle' => { weight: 1.5, volume_condition: :breakout, confirmation: :resistance_hold }, 'belt_hold_bearish' => { weight: 1.2, volume_condition: :high, confirmation: :next_candle_confirmation }, 'falling_three_methods' => { weight: 1.3, volume_condition: :sustained, confirmation: :continuation }, 'three_line_strike_bearish' => { weight: 1.3, volume_condition: :breakout, confirmation: :volume_spike }, 'identical_three_crows' => { weight: 1.3, volume_condition: :high, confirmation: :volume_confirmation } }.freeze def analyze bullish = @current.patterns.select { |p| BULLISH_PATTERNS.key?(p) } bearish = @current.patterns.select { |p| BEARISH_PATTERNS.key?(p) } { bullish_patterns: bullish, bearish_patterns: bearish, bullish_score: bullish.sum { |p| BULLISH_PATTERNS[p][:weight] }, bearish_score: bearish.sum { |p| BEARISH_PATTERNS[p][:weight] }, net_score: bullish.sum { |p| BULLISH_PATTERNS[p][:weight] } - bearish.sum { |p| BEARISH_PATTERNS[p][:weight] }, strongest_pattern: find_strongest_pattern(bullish + bearish), volume_analysis: analyze_pattern_volume(bullish + bearish), confirmations: check_confirmations(bullish + bearish), pattern_combinations: analyze_pattern_combinations(bullish, bearish), multi_timeframe_confirmation: check_multi_timeframe_confirmation(bullish + bearish), trend_alignment: check_trend_alignment(bullish + bearish), pattern_trend: analyze_pattern_trend } end private def analyze_pattern_combinations(bullish, bearish) combinations = { reversal_combinations: check_reversal_combinations(bullish, bearish), continuation_combinations: check_continuation_combinations(bullish, bearish), volume_confirmation_combinations: check_volume_confirmation_combinations(bullish + bearish), indicator_confirmation_combinations: check_indicator_confirmation_combinations(bullish + bearish) } combinations.merge!(find_high_probability_combinations(bullish, bearish)) combinations end def check_reversal_combinations(bullish, bearish) { double_bottom_with_hammer: bullish.include?('double_bottom') && bullish.include?('hammer'), head_and_shoulders_with_volume: bearish.include?('head_and_shoulders') && check_volume_condition(:breakout), morning_star_with_rsi: bullish.include?('morning_star') && @current.rsi_14 < 30, evening_star_with_macd: bearish.include?('evening_star') && @current.macd_line < @current.macd_signal } end def check_continuation_combinations(bullish, bearish) { flag_with_volume: (bullish.include?('flag_bullish') || bearish.include?('flag_bearish')) && check_volume_condition(:breakout), pennant_with_trend: (bullish.include?('pennant_bullish') && @current.trend_slope > 0) || (bearish.include?('pennant_bearish') && @current.trend_slope < 0), triangle_with_breakout: (bullish.include?('ascending_triangle') && @current.close > @current.resistance_level) || (bearish.include?('descending_triangle') && @current.close < @current.support_level) } end def check_volume_confirmation_combinations(patterns) patterns.each_with_object({}) do |pattern, result| condition = if BULLISH_PATTERNS.key?(pattern) BULLISH_PATTERNS[pattern][:volume_condition] else BEARISH_PATTERNS[pattern][:volume_condition] end result[pattern] = check_volume_condition(condition) end end def check_indicator_confirmation_combinations(patterns) patterns.each_with_object({}) do |pattern, result| confirmation = if BULLISH_PATTERNS.key?(pattern) BULLISH_PATTERNS[pattern][:confirmation] else BEARISH_PATTERNS[pattern][:confirmation] end result[pattern] = check_confirmation(confirmation) end end def find_high_probability_combinations(bullish, bearish) high_prob = {} if bullish.include?('three_white_soldiers') && bullish.include?('volume_breakout') && @current.trend_slope > 0 high_prob[:strong_bullish_continuation] = true end if bearish.include?('three_black_crows') && bearish.include?('volume_spike') && @current.trend_slope < 0 high_prob[:strong_bearish_continuation] = true end if bullish.include?('hammer') && bullish.include?('double_bottom') && @current.rsi_14 < 30 high_prob[:bullish_reversal_combo] = true end if bearish.include?('gravestone_doji') && bearish.include?('head_and_shoulders') && @current.rsi_14 > 70 high_prob[:bearish_reversal_combo] = true end high_prob end def check_multi_timeframe_confirmation(patterns) return {} unless @history.size >= 5 patterns.each_with_object({}) do |pattern, result| higher_tf_confirmed = case pattern when *BULLISH_PATTERNS.keys @history.last(3).any? { |i| i.patterns.include?(pattern) } && @current.trend_slope > 0 when *BEARISH_PATTERNS.keys @history.last(3).any? { |i| i.patterns.include?(pattern) } && @current.trend_slope < 0 else false end result[pattern] = higher_tf_confirmed end end def check_trend_alignment(patterns) patterns.each_with_object({}) do |pattern, result| aligned = case pattern when *BULLISH_PATTERNS.keys @current.trend_slope > 0 || @current.ema_8 > @current.ema_20 when *BEARISH_PATTERNS.keys @current.trend_slope < 0 || @current.ema_8 < @current.ema_20 else false end result[pattern] = aligned end end def find_strongest_pattern(patterns) return nil if patterns.empty? patterns.max_by do |pattern| if BULLISH_PATTERNS.key?(pattern) BULLISH_PATTERNS[pattern][:weight] else BEARISH_PATTERNS[pattern][:weight] end end end def analyze_pattern_volume(patterns) patterns.each_with_object({}) do |pattern, result| condition = if BULLISH_PATTERNS.key?(pattern) BULLISH_PATTERNS[pattern][:volume_condition] else BEARISH_PATTERNS[pattern][:volume_condition] end result[pattern] = { condition: condition, current_volume: @current.volume, volume_ratio: (@current.volume.to_f / @avg_volume).round(2), meets_condition: check_volume_condition(condition) } end end def check_volume_condition(condition) ratio = @current.volume.to_f / @avg_volume case condition when :extreme then ratio > 3.0 when :high then ratio > 1.5 when :normal then ratio.between?(0.75, 1.5) when :low then ratio < 0.75 when :sustained then check_sustained_volume when :breakout then ratio > 2.0 && @current.close > @current.resistance_level when :none then true else false end end def check_sustained_volume return false unless @history.size >= 3 @history.last(3).all? { |i| i.volume > @avg_volume * 1.2 } end def check_confirmations(patterns) patterns.each_with_object({}) do |pattern, result| confirmation_type = if BULLISH_PATTERNS.key?(pattern) BULLISH_PATTERNS[pattern][:confirmation] else BEARISH_PATTERNS[pattern][:confirmation] end result[pattern] = { confirmation_type: confirmation_type, confirmed: check_confirmation(confirmation_type) } end end def check_confirmation(confirmation_type) case confirmation_type when :ema_cross @current.ema_8 > @current.ema_20 && @current.ema_20 > @current.ema_50 when :volume_increase @current.volume > @history.last(3).map(&:volume).max when :resistance_break @current.close > @current.resistance_level when :follow_through @candles[-1].close > @candles[-2].high when :third_candle_confirmation @candles.size >= 3 && @candles[-1].close > @candles[-3].high when :next_candle_confirmation @candles.size >= 2 && @candles[-1].close > @candles[-2].close when :next_candle_bullish @candles.size >= 2 && @candles[-1].bullish? when :continuation @current.trend_slope > 0 when :neckline_break @current.close > @current.resistance_level when :rsi_oversold @current.rsi_14 < 30 when :gap_hold @candles.size >= 2 && (@candles[-1].low > @candles[-2].high || @candles[-1].high < @candles[-2].low) when :trend_confirmation @current.trend_slope > 0 && @current.macd_line > @current.macd_signal when :wedge_breakout (@current.bollinger_upper - @current.bollinger_lower) < (@current.keltner_upper - @current.keltner_lower) when :flag_pole_ratio (@current.close - @current.low) / (@current.high - @current.low) > 0.7 when :volume_contraction @current.volume < @history.last(3).map(&:volume).average when :support_hold @current.close > @current.support_level when :volume_spike @current.volume > @history.last(5).map(&:volume).max when :macd_line_cross @current.macd_line > @current.macd_signal when :price_rejection @current.close < @current.open && @current.upper_shadow > (@current.high - @current.low) * 0.6 when :gap_fill @candles.size >= 3 && @candles[-1].close.between?(@candles[-3].low, @candles[-3].high) when :support_break @current.close < @current.support_level when :resistance_hold @current.close < @current.resistance_level when :handle_breakout @current.close > @current.resistance_level && @current.volume > @avg_volume * 1.5 when :next_candle_bearish @candles.size >= 2 && @candles[-1].bearish? when :breakout_direction (@current.bollinger_upper - @current.bollinger_lower) > (@history[-3].bollinger_upper - @history[-3].bollinger_lower) when :volume_confirmation @current.volume > @avg_volume * 1.5 else false end end def analyze_pattern_trend { short_term: { ema_8_vs_20: @current.ema_8 > @current.ema_20 ? :bullish : :bearish, rsi: @current.rsi_14 > 50 ? :bullish : :bearish, macd: @current.macd_line > @current.macd_signal ? :bullish : :bearish }, medium_term: { ema_20_vs_50: @current.ema_20 > @current.ema_50 ? :bullish : :bearish, trend_slope: @current.trend_slope > 0 ? :bullish : :bearish, adx: @current.adx > 25 ? :strong_trend : :weak_trend } } end end end
Editor is loading...
Leave a Comment