Skip to content

Latest commit

 

History

History
337 lines (257 loc) · 8.83 KB

File metadata and controls

337 lines (257 loc) · 8.83 KB

Technical Indicators Engine

A high-performance, concurrent technical indicators library written in Go. This engine provides efficient implementations of common technical analysis indicators used in financial markets, with built-in caching, concurrent processing, and comprehensive configuration options.

Features

  • Multiple Technical Indicators: SMA, EMA, RSI, MACD
  • High Performance: Optimized algorithms with O(n) time complexity
  • Concurrent Processing: Built-in worker pools for parallel calculations
  • Intelligent Caching: LRU cache for frequently used calculations
  • Flexible Configuration: JSON/YAML configuration support with presets
  • Comprehensive Error Handling: Structured error types with context
  • Type Safety: Strong typing with validation throughout
  • Extensible Architecture: Easy to add new indicators

Quick Start

Installation

go mod init your-project
go get github.com/your-username/technical-indicators-engine

Basic Usage

package main

import (
    "fmt"
    "time"
    "technical-indicators-engine/pkg/types"
    "technical-indicators-engine/pkg/indicators"
)

func main() {
    // Create sample price data
    data := []types.PriceData{
        {Timestamp: time.Now(), Close: 100.0},
        {Timestamp: time.Now(), Close: 102.0},
        {Timestamp: time.Now(), Close: 101.0},
        {Timestamp: time.Now(), Close: 103.0},
        {Timestamp: time.Now(), Close: 105.0},
    }
    
    timeSeries := types.NewTimeSeries(data)
    
    // Create and calculate SMA
    config := types.IndicatorConfig{Period: 3}
    sma := indicators.NewSMA(config)
    
    results, err := sma.Calculate(timeSeries)
    if err != nil {
        panic(err)
    }
    
    for _, result := range results {
        fmt.Printf("SMA: %.2f at %d\n", result.Value, result.Timestamp)
    }
}

Supported Indicators

Simple Moving Average (SMA)

Calculates the arithmetic mean of closing prices over a specified period.

config := types.IndicatorConfig{Period: 20}
sma := indicators.NewSMA(config)
results, err := sma.Calculate(timeSeries)

Exponential Moving Average (EMA)

Gives more weight to recent prices, making it more responsive to new information.

config := types.IndicatorConfig{Period: 20}
ema := indicators.NewEMA(config)
results, err := ema.Calculate(timeSeries)

Relative Strength Index (RSI)

Momentum oscillator that measures the speed and magnitude of price changes (0-100 scale).

config := types.IndicatorConfig{Period: 14}
rsi := indicators.NewRSI(config)
results, err := rsi.Calculate(timeSeries)

// Check for overbought/oversold conditions
for _, result := range results {
    if rsi.IsOverbought(result.Value, 70) {
        fmt.Println("Overbought condition")
    }
    if rsi.IsOversold(result.Value, 30) {
        fmt.Println("Oversold condition")
    }
}

MACD (Moving Average Convergence Divergence)

Trend-following momentum indicator that shows relationships between two moving averages.

config := types.IndicatorConfig{
    Period: 12,
    Params: map[string]interface{}{
        "fast_period":   12,
        "slow_period":   26,
        "signal_period": 9,
    },
}
macd := indicators.NewMACD(config)
results, err := macd.Calculate(timeSeries)

Configuration System

Using Configuration Files

# indicators.yaml
indicators:
  sma_20:
    type: "sma"
    period: 20
  
  rsi_14:
    type: "rsi"
    period: 14
  
  macd_default:
    type: "macd"
    period: 12
    params:
      fast_period: 12
      slow_period: 26
      signal_period: 9
import "technical-indicators-engine/pkg/config"

// Load configuration
cfg, err := config.LoadFromFile("indicators.yaml")
if err != nil {
    panic(err)
}

// Create indicators from config
builder := builder.NewIndicatorBuilder()
indicators, err := builder.BuildFromConfig(cfg)

Using Presets

import "technical-indicators-engine/pkg/presets"

// Use predefined configurations
smaConfig := presets.GetSMAPreset("short") // 10-period SMA
rsiConfig := presets.GetRSIPreset("standard") // 14-period RSI
macdConfig := presets.GetMACDPreset("default") // 12,26,9 MACD

Concurrent Processing

Process multiple indicators in parallel using the built-in worker pool:

import "technical-indicators-engine/pkg/indicators"

// Create concurrent calculator
concurrent := indicators.NewConcurrentCalculator(4) // 4 workers

// Add multiple indicators
concurrent.AddIndicator("sma_20", indicators.NewSMA(types.IndicatorConfig{Period: 20}))
concurrent.AddIndicator("rsi_14", indicators.NewRSI(types.IndicatorConfig{Period: 14}))
concurrent.AddIndicator("ema_10", indicators.NewEMA(types.IndicatorConfig{Period: 10}))

// Calculate all indicators concurrently
results, err := concurrent.CalculateAll(timeSeries)
if err != nil {
    panic(err)
}

for name, result := range results {
    fmt.Printf("%s: %v\n", name, result)
}

Caching

Enable caching for improved performance with repeated calculations:

import "technical-indicators-engine/pkg/indicators"

// Create cached indicator
sma := indicators.NewSMA(types.IndicatorConfig{Period: 20})
cachedSMA := indicators.NewCachedIndicator(sma, 100) // Cache up to 100 results

// Subsequent calculations with same data will use cache
results1, _ := cachedSMA.Calculate(timeSeries) // Calculated
results2, _ := cachedSMA.Calculate(timeSeries) // Retrieved from cache

Error Handling

The library provides comprehensive error handling with structured error types:

results, err := sma.Calculate(timeSeries)
if err != nil {
    // Check specific error types
    if errors.IsErrorCode(err, errors.ErrCodeInsufficientData) {
        fmt.Println("Not enough data points for calculation")
        fmt.Printf("Required: %d, Available: %d\n", 
            period, len(timeSeries.Data))
    }
    
    // Get error context
    if context := errors.GetErrorContext(err); context != nil {
        fmt.Printf("Error context: %v\n", context)
    }
}

Performance

Benchmarks

The library is optimized for performance with the following characteristics:

  • SMA: O(n) time complexity using sliding window
  • EMA: O(n) time complexity with single pass
  • RSI: O(n) time complexity with efficient gain/loss calculation
  • MACD: O(n) time complexity combining multiple EMAs

Memory Usage

  • Efficient memory allocation with pre-sized slices
  • Optional result caching with configurable limits
  • Minimal garbage collection pressure

Testing

Run the comprehensive test suite:

# Run all tests
go test ./...

# Run with coverage
go test -cover ./...

# Run benchmarks
go test -bench=. ./...

# Run specific indicator tests
go test ./pkg/indicators -v

Architecture

technical-indicators-engine/
├── pkg/
│   ├── types/          # Core data types and interfaces
│   ├── indicators/     # Indicator implementations
│   ├── config/         # Configuration management
│   ├── builder/        # Indicator factory and builder
│   ├── presets/        # Predefined configurations
│   └── errors/         # Error types and handling
├── internal/
│   ├── cache/          # LRU caching implementation
│   ├── pool/           # Worker pool for concurrency
│   ├── validation/     # Input validation
│   └── benchmark/      # Performance benchmarking
└── cmd/                # Example applications

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Adding New Indicators

To add a new indicator:

  1. Create a new file in pkg/indicators/
  2. Implement the types.Indicator interface
  3. Add factory function and register it
  4. Add comprehensive tests
  5. Update documentation
// Example: Adding a new indicator
type NewIndicator struct {
    types.BaseIndicator
    validator *validation.Validator
}

func (n *NewIndicator) Calculate(data *types.TimeSeries) ([]types.IndicatorResult, error) {
    // Implementation here
}

func NewNewIndicatorFactory(config types.IndicatorConfig) (types.Indicator, error) {
    // Validation and creation logic
    return &NewIndicator{}, nil
}

// Register in init function
func init() {
    indicators.Register("new_indicator", NewNewIndicatorFactory)
}

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • Thanks to the financial analysis community for indicator specifications
  • Inspired by popular technical analysis libraries in other languages
  • Built with performance and reliability in mind for production use

For more detailed documentation, please refer to the GoDoc.