148 lines
3.4 KiB
Go
148 lines
3.4 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// LoadYAMLOrEnv loads configuration from YAML file or falls back to environment variables
|
|
func LoadYAMLOrEnv() (*Config, error) {
|
|
// Check for config file (in order of preference)
|
|
configPaths := []string{
|
|
os.Getenv("CONFIG_FILE"), // Highest priority
|
|
"./config.yaml",
|
|
"./config.yml",
|
|
filepath.Join(os.Getenv("HOME"), ".config/aitrade/config.yaml"),
|
|
"/etc/aitrade/config.yaml",
|
|
}
|
|
|
|
for _, path := range configPaths {
|
|
if path == "" {
|
|
continue
|
|
}
|
|
|
|
if _, err := os.Stat(path); err == nil {
|
|
cfg, err := loadYAMLFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load %s: %w", path, err)
|
|
}
|
|
fmt.Printf("Loaded configuration from: %s\n", path)
|
|
return cfg, nil
|
|
}
|
|
}
|
|
|
|
// Fall back to environment variables
|
|
return Load()
|
|
}
|
|
|
|
// loadYAMLFile loads and parses a YAML configuration file
|
|
func loadYAMLFile(path string) (*Config, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read file: %w", err)
|
|
}
|
|
|
|
var cfg Config
|
|
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
|
return nil, fmt.Errorf("failed to parse YAML: %w", err)
|
|
}
|
|
|
|
// Apply defaults for empty values
|
|
applyDefaults(&cfg)
|
|
|
|
return &cfg, cfg.Validate()
|
|
}
|
|
|
|
// applyDefaults sets default values for empty fields
|
|
func applyDefaults(cfg *Config) {
|
|
if cfg.IBGateway.Host == "" {
|
|
cfg.IBGateway.Host = "127.0.0.1"
|
|
}
|
|
if cfg.IBGateway.Port == 0 {
|
|
cfg.IBGateway.Port = 4001
|
|
}
|
|
if cfg.IBGateway.ClientID == 0 {
|
|
cfg.IBGateway.ClientID = 1
|
|
}
|
|
if cfg.IBGateway.MarketDataType == 0 {
|
|
cfg.IBGateway.MarketDataType = 3 // Default: Delayed (15min, kostenlos)
|
|
}
|
|
|
|
if cfg.Trading.Strategy == "" {
|
|
cfg.Trading.Strategy = "normal"
|
|
}
|
|
if cfg.Trading.StopLossPercent == 0.0 {
|
|
cfg.Trading.StopLossPercent = 3.0
|
|
}
|
|
if cfg.Trading.MaxTradesPerHour == 0 {
|
|
cfg.Trading.MaxTradesPerHour = 6
|
|
}
|
|
if cfg.Trading.MaxParallelTrades == 0 {
|
|
cfg.Trading.MaxParallelTrades = 5
|
|
}
|
|
if cfg.Trading.PendingTime.Duration == 0 {
|
|
cfg.Trading.PendingTime.Duration = 300 * time.Second
|
|
}
|
|
if cfg.Trading.DryRunBalance == 0.0 {
|
|
cfg.Trading.DryRunBalance = 100000.0
|
|
}
|
|
if cfg.Trading.TradingInterval.Duration == 0 {
|
|
cfg.Trading.TradingInterval.Duration = 60 * time.Second
|
|
}
|
|
if len(cfg.Trading.WatchSymbols) == 0 {
|
|
cfg.Trading.WatchSymbols = []string{"AAPL", "MSFT", "GOOGL", "TSLA", "AMZN"}
|
|
}
|
|
if cfg.Trading.TakeProfitPercent == 0.0 {
|
|
cfg.Trading.TakeProfitPercent = 5.0
|
|
}
|
|
if cfg.Trading.HoldTimeMinutes == 0 {
|
|
cfg.Trading.HoldTimeMinutes = 30
|
|
}
|
|
|
|
if cfg.Database.Path == "" {
|
|
cfg.Database.Path = "./data/aitrade.db"
|
|
}
|
|
|
|
if cfg.Web.Port == "" {
|
|
cfg.Web.Port = "8080"
|
|
}
|
|
if cfg.Web.Host == "" {
|
|
cfg.Web.Host = "0.0.0.0"
|
|
}
|
|
|
|
if len(cfg.OIDC.Scopes) == 0 {
|
|
cfg.OIDC.Scopes = []string{"openid", "profile", "email"}
|
|
}
|
|
|
|
if cfg.News.PollInterval.Duration == 0 {
|
|
cfg.News.PollInterval.Duration = 300 * time.Second
|
|
}
|
|
|
|
if cfg.LLMScorer.Endpoint == "" {
|
|
cfg.LLMScorer.Endpoint = "http://localhost:11434"
|
|
}
|
|
if cfg.LLMScorer.ModelName == "" {
|
|
cfg.LLMScorer.ModelName = "mistral"
|
|
}
|
|
if cfg.LLMScorer.Timeout.Duration == 0 {
|
|
cfg.LLMScorer.Timeout.Duration = 30 * time.Second
|
|
}
|
|
if cfg.LLMScorer.Temperature == 0.0 {
|
|
cfg.LLMScorer.Temperature = 0.3
|
|
}
|
|
if cfg.LLMScorer.MaxRetries == 0 {
|
|
cfg.LLMScorer.MaxRetries = 2
|
|
}
|
|
if cfg.LLMScorer.EnsembleWeight == 0.0 {
|
|
cfg.LLMScorer.EnsembleWeight = 0.7
|
|
}
|
|
|
|
if cfg.LogLevel == "" {
|
|
cfg.LogLevel = "info"
|
|
}
|
|
}
|