Class: SQA::MultiTimeframe
- Inherits:
-
Object
- Object
- SQA::MultiTimeframe
- Defined in:
- lib/sqa/multi_timeframe.rb
Overview
MultiTimeframe - Analyze patterns across multiple timeframes
Provides methods for:
-
Timeframe conversion (daily → weekly → monthly)
-
Multi-timeframe signal confirmation
-
Trend alignment across timeframes
-
Support/resistance across timeframes
Common timeframe strategy:
-
Use higher timeframe for trend direction
-
Use lower timeframe for entry timing
Instance Attribute Summary collapse
-
#stock ⇒ Object
readonly
Returns the value of attribute stock.
-
#timeframes ⇒ Object
readonly
Returns the value of attribute timeframes.
Instance Method Summary collapse
-
#confirmation(strategy_class:) ⇒ Hash
Check if timeframes confirm each other.
-
#convert_timeframes ⇒ Object
Convert daily data to weekly and monthly.
-
#detect_divergence ⇒ Hash
Detect divergence across timeframes.
-
#indicators(indicator:, **options) ⇒ Hash
Calculate indicators for each timeframe.
-
#initialize(stock:) ⇒ MultiTimeframe
constructor
Initialize multi-timeframe analyzer.
-
#signal(strategy_class:, higher_timeframe: :weekly, lower_timeframe: :daily) ⇒ Symbol
Generate multi-timeframe signal.
-
#support_resistance(tolerance: 0.02) ⇒ Hash
Find support/resistance levels across timeframes.
-
#trend_alignment(lookback: 20) ⇒ Hash
Check trend alignment across timeframes.
Constructor Details
#initialize(stock:) ⇒ MultiTimeframe
Initialize multi-timeframe analyzer
31 32 33 34 35 36 37 |
# File 'lib/sqa/multi_timeframe.rb', line 31 def initialize(stock:) @stock = stock @timeframes = {} # Convert daily data to other timeframes convert_timeframes end |
Instance Attribute Details
#stock ⇒ Object (readonly)
Returns the value of attribute stock.
24 25 26 |
# File 'lib/sqa/multi_timeframe.rb', line 24 def stock @stock end |
#timeframes ⇒ Object (readonly)
Returns the value of attribute timeframes.
24 25 26 |
# File 'lib/sqa/multi_timeframe.rb', line 24 def timeframes @timeframes end |
Instance Method Details
#confirmation(strategy_class:) ⇒ Hash
Check if timeframes confirm each other
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/sqa/multi_timeframe.rb', line 228 def confirmation(strategy_class:) signals = {} @timeframes.each do |timeframe, data| vector = create_vector(data) signals[timeframe] = strategy_class.trade(vector) end # Check agreement buy_count = signals.values.count(:buy) sell_count = signals.values.count(:sell) { signals: signals, confirmed: buy_count >= 2 || sell_count >= 2, consensus: if buy_count >= 2 :buy elsif sell_count >= 2 :sell else :hold end } end |
#convert_timeframes ⇒ Object
Convert daily data to weekly and monthly
42 43 44 45 46 47 48 |
# File 'lib/sqa/multi_timeframe.rb', line 42 def convert_timeframes daily_data = @stock.df.data @timeframes[:daily] = daily_data @timeframes[:weekly] = resample(daily_data, period: 5) @timeframes[:monthly] = resample(daily_data, period: 21) end |
#detect_divergence ⇒ Hash
Detect divergence across timeframes
Divergence occurs when price and indicator move in opposite directions.
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/sqa/multi_timeframe.rb', line 197 def detect_divergence divergences = {} @timeframes.each do |timeframe, data| prices = data["adj_close_price"].to_a rsi = SQAI.rsi(prices, period: 14) next if prices.size < 20 || rsi.size < 20 # Compare last 10 periods price_trend = prices[-1] > prices[-10] rsi_trend = rsi[-1] > rsi[-10] divergences[timeframe] = if price_trend && !rsi_trend :bearish_divergence elsif !price_trend && rsi_trend :bullish_divergence else :no_divergence end end divergences end |
#indicators(indicator:, **options) ⇒ Hash
Calculate indicators for each timeframe
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/sqa/multi_timeframe.rb', line 167 def indicators(indicator:, **) results = {} @timeframes.each do |timeframe, data| prices = data["adj_close_price"].to_a results[timeframe] = case indicator when :sma SQAI.sma(prices, **) when :ema SQAI.ema(prices, **) when :rsi SQAI.rsi(prices, **) when :macd SQAI.macd(prices, **) else nil end end results end |
#signal(strategy_class:, higher_timeframe: :weekly, lower_timeframe: :daily) ⇒ Symbol
Generate multi-timeframe signal
Uses higher timeframe for trend, lower for timing.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/sqa/multi_timeframe.rb', line 102 def signal(strategy_class:, higher_timeframe: :weekly, lower_timeframe: :daily) # Get trend from higher timeframe higher_data = @timeframes[higher_timeframe] higher_prices = higher_data["adj_close_price"].to_a higher_trend = if higher_prices.last > higher_prices[-10..-1].sum / 10.0 :up else :down end # Get signal from lower timeframe lower_data = @timeframes[lower_timeframe] lower_vector = create_vector(lower_data) lower_signal = strategy_class.trade(lower_vector) # Combine: only take trades aligned with higher timeframe case higher_trend when :up lower_signal == :buy ? :buy : :hold when :down lower_signal == :sell ? :sell : :hold else :hold end end |
#support_resistance(tolerance: 0.02) ⇒ Hash
Find support/resistance levels across timeframes
Levels that appear on multiple timeframes are stronger.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/sqa/multi_timeframe.rb', line 138 def support_resistance(tolerance: 0.02) all_levels = { support: [], resistance: [] } @timeframes.each do |timeframe, data| prices = data["adj_close_price"].to_a levels = find_levels(prices) all_levels[:support] += levels[:support].map { |l| { price: l, timeframe: timeframe } } all_levels[:resistance] += levels[:resistance].map { |l| { price: l, timeframe: timeframe } } end # Find levels that appear on multiple timeframes strong_support = cluster_levels(all_levels[:support], tolerance) strong_resistance = cluster_levels(all_levels[:resistance], tolerance) { support: strong_support, resistance: strong_resistance, current_price: @stock.df.data["adj_close_price"].to_a.last } end |
#trend_alignment(lookback: 20) ⇒ Hash
Check trend alignment across timeframes
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/sqa/multi_timeframe.rb', line 56 def trend_alignment(lookback: 20) trends = {} @timeframes.each do |timeframe, data| prices = data["adj_close_price"].to_a recent = prices.last([lookback, prices.size].min) # Simple trend: compare current to average current = recent.last avg = recent.sum / recent.size.to_f trends[timeframe] = if current > avg * 1.02 :up elsif current < avg * 0.98 :down else :sideways end end # Check if all timeframes aligned all_up = trends.values.all? { |t| t == :up } all_down = trends.values.all? { |t| t == :down } trends[:aligned] = all_up || all_down trends[:direction] = if all_up :bullish elsif all_down :bearish else :mixed end trends end |