Class: TA::TechnicalAnalysis

Inherits:
Object
  • Object
show all
Defined in:
lib/ta/technical_analysis.rb

Overview

Main technical analysis orchestrator for multi-timeframe indicator computation

Constant Summary collapse

DEFAULTS =
{
  rsi_period: 14,
  atr_period: 14,
  adx_period: 14,
  macd_fast: 12,
  macd_slow: 26,
  macd_signal: 9,
  throttle_seconds: 1.0,
  max_retries: 3
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ TechnicalAnalysis

Returns a new instance of TechnicalAnalysis.



39
40
41
42
# File 'lib/ta/technical_analysis.rb', line 39

def initialize(options = {})
  @opts = DEFAULTS.merge(options.transform_keys(&:to_sym))
  @fetcher = Fetcher.new(throttle_seconds: @opts[:throttle_seconds], max_retries: @opts[:max_retries])
end

Instance Method Details

#compute(exchange_segment:, instrument:, security_id:, from_date: nil, to_date: nil, days_back: nil, intervals: [1, 5, 15, 25, 60]) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
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
# File 'lib/ta/technical_analysis.rb', line 44

def compute(exchange_segment:, instrument:, security_id:, from_date: nil, to_date: nil, days_back: nil,
            intervals: [1, 5, 15, 25, 60])
  # Normalize to_date: default to last trading day; if provided and non-trading, roll back
  to_date = normalize_to_date(to_date)

  # Auto-calculate required trading days if not provided
  days_back = auto_days_needed(intervals) if days_back.nil? || days_back.to_i <= 0

  # Derive/normalize from_date
  from_date = normalize_from_date(from_date, to_date, days_back)

  base_params = {
    exchange_segment: exchange_segment,
    instrument: instrument,
    security_id: security_id,
    from_date: from_date,
    to_date: to_date
  }

  frames = {}
  interval_key = { 1 => :m1, 5 => :m5, 15 => :m15, 25 => :m25, 60 => :m60 }
  intervals.each do |ivl|
    key = interval_key[ivl.to_i]
    next unless key

    raw = @fetcher.intraday_windowed(base_params, ivl.to_i)
    frames[key] = Candles.from_series(raw)
    sleep_with_jitter # throttle between intervals
  end

  {
    meta: {
      exchange_segment: exchange_segment,
      instrument: instrument,
      security_id: security_id,
      from_date: from_date,
      to_date: to_date
    },
    indicators: frames.transform_values { |candles| compute_for(candles) }
  }
end

#compute_from_file(path:, base_interval: 1, intervals: [1, 5, 15, 25, 60]) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ta/technical_analysis.rb', line 86

def compute_from_file(path:, base_interval: 1, intervals: [1, 5, 15, 25, 60])
  raw = JSON.parse(File.read(path))
  base = Candles.from_series(raw)
  frames = {}
  intervals.each do |ivl|
    case ivl.to_i
    when 1 then frames[:m1]   = (base_interval == 1 ? base : Candles.resample(base, 1))
    when 5 then frames[:m5]   = Candles.resample(base, 5)
    when 15 then frames[:m15] = Candles.resample(base, 15)
    when 25 then frames[:m25] = Candles.resample(base, 25)
    when 60 then frames[:m60] = Candles.resample(base, 60)
    end
  end
  { indicators: frames.transform_values { |candles| compute_for(candles) } }
end