Module: SQA::SeasonalAnalyzer
- Defined in:
- lib/sqa/seasonal_analyzer.rb
Class Method Summary collapse
-
.analyze(stock) ⇒ Hash
Analyze seasonal performance patterns.
-
.context_for_date(date) ⇒ Hash
Get seasonal context for a specific date.
-
.detect_seasonality(monthly_returns) ⇒ Boolean
Detect if stock has seasonal pattern.
-
.filter_by_months(stock, months) ⇒ Hash
Filter data by calendar months.
-
.filter_by_quarters(stock, quarters) ⇒ Hash
Filter data by quarters.
Class Method Details
.analyze(stock) ⇒ Hash
Analyze seasonal performance patterns
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/sqa/seasonal_analyzer.rb', line 25 def analyze(stock) df = stock.df # Extract dates and prices (handle both 'date' and 'timestamp' column names) date_column = df.data.columns.include?("date") ? "date" : "timestamp" dates = df[date_column].to_a.map { |d| Date.parse(d.to_s) } prices = df["adj_close_price"].to_a # Calculate monthly returns monthly_returns = calculate_monthly_returns(dates, prices) quarterly_returns = calculate_quarterly_returns(dates, prices) { monthly_returns: monthly_returns, quarterly_returns: quarterly_returns, best_months: rank_months(monthly_returns).first(3), worst_months: rank_months(monthly_returns).last(3), best_quarters: rank_quarters(quarterly_returns).first(2), worst_quarters: rank_quarters(quarterly_returns).last(2), has_seasonal_pattern: detect_seasonality(monthly_returns) } end |
.context_for_date(date) ⇒ Hash
Get seasonal context for a specific date
116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/sqa/seasonal_analyzer.rb', line 116 def context_for_date(date) { month: date.month, quarter: ((date.month - 1) / 3) + 1, month_name: Date::MONTHNAMES[date.month], quarter_name: "Q#{((date.month - 1) / 3) + 1}", is_year_end: [11, 12].include?(date.month), is_year_start: [1, 2].include?(date.month), is_holiday_season: [11, 12].include?(date.month), is_earnings_season: [1, 4, 7, 10].include?(date.month) } end |
.detect_seasonality(monthly_returns) ⇒ Boolean
Detect if stock has seasonal pattern
99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/sqa/seasonal_analyzer.rb', line 99 def detect_seasonality(monthly_returns) returns = monthly_returns.values.map { |stats| stats[:avg_return] } # Check variance in monthly returns mean = returns.sum / returns.size variance = returns.map { |r| (r - mean)**2 }.sum / returns.size std_dev = Math.sqrt(variance) # If standard deviation of monthly returns is high, likely seasonal std_dev > 2.0 end |
.filter_by_months(stock, months) ⇒ Hash
Filter data by calendar months
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/sqa/seasonal_analyzer.rb', line 56 def filter_by_months(stock, months) df = stock.df date_column = df.data.columns.include?("date") ? "date" : "timestamp" dates = df[date_column].to_a.map { |d| Date.parse(d.to_s) } prices = df["adj_close_price"].to_a indices = [] dates.each_with_index do |date, i| indices << i if months.include?(date.month) end { indices: indices, dates: indices.map { |i| dates[i] }, prices: indices.map { |i| prices[i] } } end |
.filter_by_quarters(stock, quarters) ⇒ Hash
Filter data by quarters
82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/sqa/seasonal_analyzer.rb', line 82 def filter_by_quarters(stock, quarters) quarter_months = { 1 => [1, 2, 3], 2 => [4, 5, 6], 3 => [7, 8, 9], 4 => [10, 11, 12] } months = quarters.flat_map { |q| quarter_months[q] } filter_by_months(stock, months) end |