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.
- 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
go mod init your-project
go get github.com/your-username/technical-indicators-enginepackage main
import (
"fmt""time""technical-indicators-engine/pkg/types""technical-indicators-engine/pkg/indicators"
)
funcmain() {
// Create sample price datadata:= []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 SMAconfig:= types.IndicatorConfig{Period: 3}
sma:=indicators.NewSMA(config)
results, err:=sma.Calculate(timeSeries)
iferr!=nil {
panic(err)
}
for_, result:=rangeresults {
fmt.Printf("SMA: %.2f at %d\n", result.Value, result.Timestamp)
}
}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)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)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 conditionsfor_, result:=rangeresults {
ifrsi.IsOverbought(result.Value, 70) {
fmt.Println("Overbought condition")
}
ifrsi.IsOversold(result.Value, 30) {
fmt.Println("Oversold condition")
}
}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)# indicators.yamlindicators:
sma_20:
type: "sma"period: 20rsi_14:
type: "rsi"period: 14macd_default:
type: "macd"period: 12params:
fast_period: 12slow_period: 26signal_period: 9import"technical-indicators-engine/pkg/config"// Load configurationcfg, err:=config.LoadFromFile("indicators.yaml")
iferr!=nil {
panic(err)
}
// Create indicators from configbuilder:=builder.NewIndicatorBuilder()
indicators, err:=builder.BuildFromConfig(cfg)import"technical-indicators-engine/pkg/presets"// Use predefined configurationssmaConfig:=presets.GetSMAPreset("short") // 10-period SMArsiConfig:=presets.GetRSIPreset("standard") // 14-period RSImacdConfig:=presets.GetMACDPreset("default") // 12,26,9 MACDProcess multiple indicators in parallel using the built-in worker pool:
import"technical-indicators-engine/pkg/indicators"// Create concurrent calculatorconcurrent:=indicators.NewConcurrentCalculator(4) // 4 workers// Add multiple indicatorsconcurrent.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 concurrentlyresults, err:=concurrent.CalculateAll(timeSeries)
iferr!=nil {
panic(err)
}
forname, result:=rangeresults {
fmt.Printf("%s: %v\n", name, result)
}Enable caching for improved performance with repeated calculations:
import"technical-indicators-engine/pkg/indicators"// Create cached indicatorsma:=indicators.NewSMA(types.IndicatorConfig{Period: 20})
cachedSMA:=indicators.NewCachedIndicator(sma, 100) // Cache up to 100 results// Subsequent calculations with same data will use cacheresults1, _:=cachedSMA.Calculate(timeSeries) // Calculatedresults2, _:=cachedSMA.Calculate(timeSeries) // Retrieved from cacheThe library provides comprehensive error handling with structured error types:
results, err:=sma.Calculate(timeSeries)
iferr!=nil {
// Check specific error typesiferrors.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 contextifcontext:=errors.GetErrorContext(err); context!=nil {
fmt.Printf("Error context: %v\n", context)
}
}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
- Efficient memory allocation with pre-sized slices
- Optional result caching with configurable limits
- Minimal garbage collection pressure
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 -vtechnical-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
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
To add a new indicator:
- Create a new file in
pkg/indicators/ - Implement the
types.Indicatorinterface - Add factory function and register it
- Add comprehensive tests
- Update documentation
// Example: Adding a new indicatortypeNewIndicatorstruct {
types.BaseIndicatorvalidator*validation.Validator
}
func (n*NewIndicator) Calculate(data*types.TimeSeries) ([]types.IndicatorResult, error) {
// Implementation here
}
funcNewNewIndicatorFactory(config types.IndicatorConfig) (types.Indicator, error) {
// Validation and creation logicreturn&NewIndicator{}, nil
}
// Register in init functionfuncinit() {
indicators.Register("new_indicator", NewNewIndicatorFactory)
}This project is licensed under the MIT License - see the LICENSE file for details.
- 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.