Untitled
unknown
plain_text
8 months ago
19 kB
8
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
endEditor is loading...
Leave a Comment