Trend Analysis Examples¶
Learn how to use SQA::TAI indicators to identify and analyze market trends.
Moving Average Crossover Strategy¶
One of the most popular trend-following strategies using moving averages.
require 'sqa/tai'
# Load historical data
prices = [44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42,
45.84, 46.08, 46.03, 46.41, 46.22, 45.64, 46.21, 46.25,
46.08, 46.46, 46.57, 45.95, 46.50, 46.02, 46.55, 47.03,
47.35, 47.28, 47.61, 48.12, 48.34, 48.21, 48.95, 49.13,
49.32, 49.78, 50.12, 50.43, 50.21, 50.67, 51.02, 51.35,
51.78, 52.12, 52.45, 52.89, 53.21, 53.65, 54.02, 54.38,
54.72, 55.15]
# Calculate fast and slow moving averages
fast_ma = SQA::TAI.sma(prices, period: 10)
slow_ma = SQA::TAI.sma(prices, period: 20)
# Detect crossovers
def detect_crossover(fast, slow)
return nil if fast[-2].nil? || slow[-2].nil?
if fast[-2] < slow[-2] && fast[-1] > slow[-1]
:bullish_crossover
elsif fast[-2] > slow[-2] && fast[-1] < slow[-1]
:bearish_crossover
else
nil
end
end
signal = detect_crossover(fast_ma, slow_ma)
case signal
when :bullish_crossover
puts "Golden Cross: Fast MA crossed above Slow MA - BUY SIGNAL"
puts "Fast MA: #{fast_ma.last.round(2)}"
puts "Slow MA: #{slow_ma.last.round(2)}"
when :bearish_crossover
puts "Death Cross: Fast MA crossed below Slow MA - SELL SIGNAL"
puts "Fast MA: #{fast_ma.last.round(2)}"
puts "Slow MA: #{slow_ma.last.round(2)}"
else
puts "No crossover detected"
end
Trend Strength Analysis¶
Combine multiple indicators to assess trend strength.
require 'sqa/tai'
def analyze_trend_strength(prices)
# Calculate multiple timeframe MAs
sma_20 = SQA::TAI.sma(prices, period: 20)
sma_50 = SQA::TAI.sma(prices, period: 50)
sma_200 = SQA::TAI.sma(prices, period: 200)
# Calculate momentum
rsi = SQA::TAI.rsi(prices, period: 14)
macd, signal, histogram = SQA::TAI.macd(prices)
current_price = prices.last
# Trend direction
trend = if current_price > sma_20.last &&
sma_20.last > sma_50.last &&
sma_50.last > sma_200.last
:strong_uptrend
elsif current_price < sma_20.last &&
sma_20.last < sma_50.last &&
sma_50.last < sma_200.last
:strong_downtrend
elsif current_price > sma_50.last
:uptrend
elsif current_price < sma_50.last
:downtrend
else
:sideways
end
# Momentum confirmation
momentum_bullish = rsi.last > 50 && macd.last > signal.last
momentum_bearish = rsi.last < 50 && macd.last < signal.last
{
trend: trend,
price: current_price.round(2),
sma_20: sma_20.last.round(2),
sma_50: sma_50.last.round(2),
sma_200: sma_200.last.round(2),
rsi: rsi.last.round(2),
macd: macd.last.round(4),
momentum_confirmed: (trend == :strong_uptrend && momentum_bullish) ||
(trend == :strong_downtrend && momentum_bearish)
}
end
# Example usage
prices = (1..100).map { |i| 100 + i * 0.5 + rand(-2.0..2.0) } # Uptrending prices
analysis = analyze_trend_strength(prices)
puts "Trend Analysis Results:"
puts "=" * 50
puts "Trend: #{analysis[:trend]}"
puts "Current Price: $#{analysis[:price]}"
puts "SMA(20): $#{analysis[:sma_20]}"
puts "SMA(50): $#{analysis[:sma_50]}"
puts "SMA(200): $#{analysis[:sma_200]}"
puts "RSI: #{analysis[:rsi]}"
puts "MACD: #{analysis[:macd]}"
puts "Momentum Confirmed: #{analysis[:momentum_confirmed] ? 'Yes' : 'No'}"
Support and Resistance with Moving Averages¶
Use moving averages as dynamic support and resistance levels.
require 'sqa/tai'
def find_ma_support_resistance(prices)
ema_20 = SQA::TAI.ema(prices, period: 20)
ema_50 = SQA::TAI.ema(prices, period: 50)
current_price = prices.last
ema_20_val = ema_20.last
ema_50_val = ema_50.last
# Determine support/resistance levels
levels = []
if current_price > ema_20_val
levels << { level: ema_20_val, type: :support, ma: "EMA(20)" }
else
levels << { level: ema_20_val, type: :resistance, ma: "EMA(20)" }
end
if current_price > ema_50_val
levels << { level: ema_50_val, type: :support, ma: "EMA(50)" }
else
levels << { level: ema_50_val, type: :resistance, ma: "EMA(50)" }
end
# Distance to levels
levels.each do |level_info|
distance = ((current_price - level_info[:level]) / level_info[:level] * 100).abs
level_info[:distance_pct] = distance.round(2)
level_info[:price] = level_info[:level].round(2)
end
levels.sort_by { |l| l[:distance_pct] }
end
# Example usage
prices = Array.new(60) { |i| 100 + Math.sin(i * 0.1) * 10 + i * 0.1 }
levels = find_ma_support_resistance(prices)
puts "Dynamic Support/Resistance Levels:"
puts "Current Price: $#{prices.last.round(2)}"
puts "\n"
levels.each do |level|
puts "#{level[:ma]}: $#{level[:price]} (#{level[:type]})"
puts " Distance: #{level[:distance_pct]}%"
end
Triple Moving Average System¶
A complete trading system using three moving averages.
require 'sqa/tai'
class TripleMASystem
def initialize(fast_period: 10, medium_period: 20, slow_period: 50)
@fast_period = fast_period
@medium_period = medium_period
@slow_period = slow_period
end
def analyze(prices)
fast = SQA::TAI.ema(prices, period: @fast_period)
medium = SQA::TAI.ema(prices, period: @medium_period)
slow = SQA::TAI.ema(prices, period: @slow_period)
current_price = prices.last
fast_val = fast.last
medium_val = medium.last
slow_val = slow.last
# Determine trend alignment
bullish_alignment = fast_val > medium_val && medium_val > slow_val
bearish_alignment = fast_val < medium_val && medium_val < slow_val
# Entry signals
signal = if bullish_alignment && current_price > fast_val
:strong_buy
elsif bearish_alignment && current_price < fast_val
:strong_sell
elsif fast_val > medium_val && current_price > fast_val
:buy
elsif fast_val < medium_val && current_price < fast_val
:sell
else
:hold
end
{
signal: signal,
price: current_price.round(2),
fast: fast_val.round(2),
medium: medium_val.round(2),
slow: slow_val.round(2),
alignment: bullish_alignment ? :bullish : (bearish_alignment ? :bearish : :mixed)
}
end
def backtest(prices, initial_capital: 10000)
capital = initial_capital
position = 0
entry_price = 0
trades = []
([@slow_period, prices.length - 1].max..prices.length - 1).each do |i|
current_prices = prices[0..i]
analysis = analyze(current_prices)
if position == 0 && [:buy, :strong_buy].include?(analysis[:signal])
# Enter long
shares = (capital / analysis[:price]).floor
position = shares
entry_price = analysis[:price]
capital -= shares * analysis[:price]
trades << {
action: :buy,
price: analysis[:price],
shares: shares,
capital: capital
}
elsif position > 0 && [:sell, :strong_sell].include?(analysis[:signal])
# Exit long
exit_value = position * analysis[:price]
capital += exit_value
profit = (analysis[:price] - entry_price) * position
trades << {
action: :sell,
price: analysis[:price],
shares: position,
profit: profit.round(2),
capital: capital.round(2)
}
position = 0
end
end
# Close any open position
if position > 0
exit_value = position * prices.last
capital += exit_value
end
{
initial_capital: initial_capital,
final_capital: capital.round(2),
total_return: ((capital / initial_capital - 1) * 100).round(2),
trades: trades
}
end
end
# Example usage
prices = Array.new(200) { |i| 100 + Math.sin(i * 0.05) * 20 + i * 0.15 + rand(-2.0..2.0) }
system = TripleMASystem.new(fast_period: 10, medium_period: 20, slow_period: 50)
# Current analysis
current_analysis = system.analyze(prices)
puts "Current Market Analysis:"
puts "Signal: #{current_analysis[:signal]}"
puts "Price: $#{current_analysis[:price]}"
puts "Fast EMA: $#{current_analysis[:fast]}"
puts "Medium EMA: $#{current_analysis[:medium]}"
puts "Slow EMA: $#{current_analysis[:slow]}"
puts "Alignment: #{current_analysis[:alignment]}"
# Backtest results
puts "\nBacktest Results:"
results = system.backtest(prices, initial_capital: 10000)
puts "Initial Capital: $#{results[:initial_capital]}"
puts "Final Capital: $#{results[:final_capital]}"
puts "Total Return: #{results[:total_return]}%"
puts "Number of Trades: #{results[:trades].length}"
Trend Following with ADX¶
Use the Average Directional Index (ADX) to measure trend strength (if available in TA-Lib).
require 'sqa/tai'
# Simplified trend strength based on moving averages
def calculate_trend_strength(prices)
sma_20 = SQA::TAI.sma(prices, period: 20)
sma_50 = SQA::TAI.sma(prices, period: 50)
# Calculate slope of 20-day MA
ma_slope = sma_20.compact.last(5).each_cons(2).map { |a, b| b - a }.sum
# Calculate distance between MAs
ma_distance = ((sma_20.last - sma_50.last) / sma_50.last * 100).abs
strength = if ma_distance > 5 && ma_slope.abs > 1
:strong
elsif ma_distance > 2 && ma_slope.abs > 0.5
:moderate
else
:weak
end
{
strength: strength,
ma_distance_pct: ma_distance.round(2),
ma_slope: ma_slope.round(4)
}
end
# Example usage
prices = Array.new(100) { |i| 100 + i * 0.8 + rand(-1.0..1.0) } # Strong uptrend
strength = calculate_trend_strength(prices)
puts "Trend Strength Analysis:"
puts "Strength: #{strength[:strength]}"
puts "MA Distance: #{strength[:ma_distance_pct]}%"
puts "MA Slope: #{strength[:ma_slope]}"