Documentation
¶
Overview ¶
Agent replay mode for backtesting with trading agents
Package backtest provides a backtesting framework for trading strategies ¶
Performance metrics calculation for backtesting ¶
Parameter optimization for backtesting strategies ¶
HTML report generation for backtest results
Index ¶
- func ExportResults(engine *Engine, filePath string) error
- func GenerateReport(metrics *Metrics) string
- func GetRecommendation(kellyPercent float64) string
- type Agent
- type AgentPerformance
- type AgentReplayAdapter
- func (a *AgentReplayAdapter) AddAgent(agent Agent) error
- func (a *AgentReplayAdapter) Finalize(engine *Engine) error
- func (a *AgentReplayAdapter) GenerateSignals(engine *Engine) ([]*Signal, error)
- func (a *AgentReplayAdapter) GetAgentMetrics() map[string]*AgentPerformance
- func (a *AgentReplayAdapter) Initialize(engine *Engine) error
- func (a *AgentReplayAdapter) PrintAgentReport() string
- func (a *AgentReplayAdapter) SetContext(key string, value interface{})
- type BacktestConfig
- type Candlestick
- type ClosedPosition
- type ConsensusStrategy
- type Engine
- func (e *Engine) ExecuteSignal(signal *Signal) error
- func (e *Engine) GetCurrentCandle(symbol string) (*Candlestick, error)
- func (e *Engine) GetCurrentEquity() float64
- func (e *Engine) GetHistoricalCandles(symbol string, lookback int) ([]*Candlestick, error)
- func (e *Engine) LoadHistoricalData(symbol string, candlesticks []*Candlestick) error
- func (e *Engine) Run(ctx context.Context, strategy Strategy) error
- func (e *Engine) Step(ctx context.Context) (bool, error)
- type EquityPoint
- type GeneticOptimizer
- type GridSearchOptimizer
- type HistoricalDataLoader
- type KellyCalculator
- type MarketData
- type Metrics
- type ObjectiveFunction
- type OptimizationResult
- type OptimizationSummary
- type ParamType
- type Parameter
- type ParameterSet
- type Position
- type ReportGenerator
- type Signal
- type Strategy
- type StrategyFactory
- type Trade
- type TradingStats
- type WalkForwardOptimizer
- type WalkForwardWindow
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExportResults ¶
ExportResults exports backtest results to JSON file
func GenerateReport ¶
GenerateReport generates a human-readable performance report
func GetRecommendation ¶
GetRecommendation provides interpretation of Kelly percentage
Types ¶
type Agent ¶
type Agent interface {
// GetName returns the agent's unique identifier
GetName() string
// Analyze receives market data and returns a trading signal
Analyze(ctx context.Context, data *MarketData) (*Signal, error)
// Reset resets the agent's internal state (for multi-run backtests)
Reset() error
}
Agent represents a trading agent that can generate signals
type AgentPerformance ¶
type AgentPerformance struct {
AgentName string `json:"agent_name"`
SignalsGenerated int `json:"signals_generated"`
BuySignals int `json:"buy_signals"`
SellSignals int `json:"sell_signals"`
HoldSignals int `json:"hold_signals"`
SignalsExecuted int `json:"signals_executed"` // Signals that resulted in trades
AvgConfidence float64 `json:"average_confidence"`
CorrectSignals int `json:"correct_signals"` // Signals that led to profitable trades
IncorrectSignals int `json:"incorrect_signals"` // Signals that led to losing trades
Accuracy float64 `json:"accuracy"` // Percentage of correct signals
}
AgentPerformance tracks individual agent performance during backtest
type AgentReplayAdapter ¶
type AgentReplayAdapter struct {
// contains filtered or unexported fields
}
AgentReplayAdapter adapts trading agents to work with the backtest engine
func NewAgentReplayAdapter ¶
func NewAgentReplayAdapter(consensus ConsensusStrategy) *AgentReplayAdapter
NewAgentReplayAdapter creates a new agent replay adapter
func (*AgentReplayAdapter) AddAgent ¶
func (a *AgentReplayAdapter) AddAgent(agent Agent) error
AddAgent registers an agent for replay
func (*AgentReplayAdapter) Finalize ¶
func (a *AgentReplayAdapter) Finalize(engine *Engine) error
Finalize implements the Strategy interface for the backtest engine
func (*AgentReplayAdapter) GenerateSignals ¶
func (a *AgentReplayAdapter) GenerateSignals(engine *Engine) ([]*Signal, error)
GenerateSignals implements the Strategy interface for the backtest engine
func (*AgentReplayAdapter) GetAgentMetrics ¶
func (a *AgentReplayAdapter) GetAgentMetrics() map[string]*AgentPerformance
GetAgentMetrics returns performance metrics for all agents
func (*AgentReplayAdapter) Initialize ¶
func (a *AgentReplayAdapter) Initialize(engine *Engine) error
Initialize implements the Strategy interface for the backtest engine
func (*AgentReplayAdapter) PrintAgentReport ¶
func (a *AgentReplayAdapter) PrintAgentReport() string
PrintAgentReport prints a summary of agent performance
func (*AgentReplayAdapter) SetContext ¶
func (a *AgentReplayAdapter) SetContext(key string, value interface{})
SetContext sets shared context data for all agents
type BacktestConfig ¶
type BacktestConfig struct {
InitialCapital float64
CommissionRate float64
PositionSizing string // "fixed", "percent", "kelly"
PositionSize float64
MaxPositions int
StartDate time.Time
EndDate time.Time
Symbols []string
}
BacktestConfig holds configuration for a backtest
type Candlestick ¶
type Candlestick struct {
Symbol string `json:"symbol"`
Timestamp time.Time `json:"timestamp"`
Open float64 `json:"open"`
High float64 `json:"high"`
Low float64 `json:"low"`
Close float64 `json:"close"`
Volume float64 `json:"volume"`
}
Candlestick represents OHLCV data for a time period
func LoadFromCSV ¶
func LoadFromCSV(filePath string) ([]*Candlestick, error)
LoadFromCSV loads historical data from a CSV file CSV format: timestamp,symbol,open,high,low,close,volume timestamp can be Unix timestamp (integer) or RFC3339 string
func LoadFromJSON ¶
func LoadFromJSON(filePath string) ([]*Candlestick, error)
LoadFromJSON loads historical data from a JSON file JSON format: array of candlestick objects or object with "candles" array
type ClosedPosition ¶
type ClosedPosition struct {
Symbol string `json:"symbol"`
Side string `json:"side"`
EntryTime time.Time `json:"entry_time"`
ExitTime time.Time `json:"exit_time"`
EntryPrice float64 `json:"entry_price"`
ExitPrice float64 `json:"exit_price"`
Quantity float64 `json:"quantity"`
RealizedPL float64 `json:"realized_pl"`
ReturnPct float64 `json:"return_pct"`
HoldingTime time.Duration `json:"holding_time"`
Commission float64 `json:"commission"`
}
ClosedPosition represents a closed position with P&L
type ConsensusStrategy ¶
type ConsensusStrategy string
ConsensusStrategy defines how signals from multiple agents are combined
const ( ConsensusMajority ConsensusStrategy = "majority" // Follow majority vote ConsensusUnanimous ConsensusStrategy = "unanimous" // All agents must agree ConsensusWeighted ConsensusStrategy = "weighted" // Weight by agent confidence ConsensusFirst ConsensusStrategy = "first" // Use first agent only ConsensusAll ConsensusStrategy = "all" // Execute all agent signals independently )
type Engine ¶
type Engine struct {
// Configuration
InitialCapital float64 `json:"initial_capital"`
CommissionRate float64 `json:"commission_rate"` // e.g., 0.001 for 0.1%
PositionSizing string `json:"position_sizing"` // "fixed", "percent", "kelly"
PositionSize float64 `json:"position_size"` // Amount per trade
MaxPositions int `json:"max_positions"` // Maximum concurrent positions
// State
Cash float64 `json:"cash"`
Positions map[string]*Position `json:"positions"` // symbol -> position
Trades []*Trade `json:"trades"`
ClosedPositions []*ClosedPosition `json:"closed_positions"`
EquityCurve []*EquityPoint `json:"equity_curve"`
// Historical data
Data map[string][]*Candlestick `json:"-"` // symbol -> candlesticks
CurrentIndex map[string]int `json:"-"` // symbol -> current index
// Statistics (calculated during backtest)
TotalTrades int `json:"total_trades"`
WinningTrades int `json:"winning_trades"`
LosingTrades int `json:"losing_trades"`
TotalProfit float64 `json:"total_profit"`
TotalLoss float64 `json:"total_loss"`
MaxDrawdown float64 `json:"max_drawdown"`
MaxDrawdownPct float64 `json:"max_drawdown_pct"`
PeakEquity float64 `json:"peak_equity"`
}
Engine is the main backtesting engine
func NewEngine ¶
func NewEngine(config BacktestConfig) *Engine
NewEngine creates a new backtesting engine
func (*Engine) ExecuteSignal ¶
ExecuteSignal executes a trading signal
func (*Engine) GetCurrentCandle ¶
func (e *Engine) GetCurrentCandle(symbol string) (*Candlestick, error)
GetCurrentCandle returns the current candlestick for a symbol
func (*Engine) GetCurrentEquity ¶
GetCurrentEquity returns current portfolio equity (cash + unrealized P&L)
func (*Engine) GetHistoricalCandles ¶
func (e *Engine) GetHistoricalCandles(symbol string, lookback int) ([]*Candlestick, error)
GetHistoricalCandles returns N candlesticks before current index
func (*Engine) LoadHistoricalData ¶
func (e *Engine) LoadHistoricalData(symbol string, candlesticks []*Candlestick) error
LoadHistoricalData loads candlestick data for backtesting
type EquityPoint ¶
type EquityPoint struct {
Timestamp time.Time `json:"timestamp"`
Equity float64 `json:"equity"`
Cash float64 `json:"cash"`
Holdings float64 `json:"holdings"`
}
EquityPoint represents portfolio equity at a point in time
type GeneticOptimizer ¶
type GeneticOptimizer struct {
// contains filtered or unexported fields
}
GeneticOptimizer performs genetic algorithm optimization
func NewGeneticOptimizer ¶
func NewGeneticOptimizer(factory StrategyFactory, params []*Parameter, objective ObjectiveFunction, config BacktestConfig) *GeneticOptimizer
NewGeneticOptimizer creates a new genetic algorithm optimizer Random seed is initialized with current time for non-deterministic behavior Use SetSeed() to set a specific seed for reproducible results
func (*GeneticOptimizer) Optimize ¶
func (opt *GeneticOptimizer) Optimize(ctx context.Context, data map[string][]*Candlestick) (*OptimizationSummary, error)
Optimize performs genetic algorithm optimization
func (*GeneticOptimizer) SetParameters ¶
func (opt *GeneticOptimizer) SetParameters(popSize, gens int, mutRate, eliteRatio float64)
SetParameters configures genetic algorithm parameters
func (*GeneticOptimizer) SetSeed ¶
func (opt *GeneticOptimizer) SetSeed(seed int64)
SetSeed sets a specific random seed for reproducible results This is useful for testing and debugging. If not called, a time-based seed is used.
type GridSearchOptimizer ¶
type GridSearchOptimizer struct {
// contains filtered or unexported fields
}
GridSearchOptimizer performs exhaustive grid search over parameter space
func NewGridSearchOptimizer ¶
func NewGridSearchOptimizer(factory StrategyFactory, params []*Parameter, objective ObjectiveFunction, config BacktestConfig) *GridSearchOptimizer
NewGridSearchOptimizer creates a new grid search optimizer
func (*GridSearchOptimizer) Optimize ¶
func (opt *GridSearchOptimizer) Optimize(ctx context.Context, data map[string][]*Candlestick) (*OptimizationSummary, error)
Optimize performs grid search optimization
func (*GridSearchOptimizer) SetParallelism ¶
func (opt *GridSearchOptimizer) SetParallelism(n int)
SetParallelism sets the number of parallel workers
type HistoricalDataLoader ¶
type HistoricalDataLoader struct {
// contains filtered or unexported fields
}
HistoricalDataLoader loads historical candlestick data from database
func NewHistoricalDataLoader ¶
func NewHistoricalDataLoader(database *db.DB) *HistoricalDataLoader
NewHistoricalDataLoader creates a new historical data loader
func (*HistoricalDataLoader) LoadFromDatabase ¶
func (h *HistoricalDataLoader) LoadFromDatabase(symbol, exchange, interval string, startDate, endDate time.Time) ([]*Candlestick, error)
LoadFromDatabase loads historical data for backtesting from TimescaleDB
type KellyCalculator ¶
type KellyCalculator struct {
// contains filtered or unexported fields
}
KellyCalculator calculates optimal position sizes using Kelly Criterion
func NewKellyCalculator ¶
func NewKellyCalculator(database *db.DB) *KellyCalculator
NewKellyCalculator creates a new Kelly Criterion calculator
func (*KellyCalculator) CalculatePositionSize ¶
func (kc *KellyCalculator) CalculatePositionSize( stats *TradingStats, capital float64, kellyFraction float64, ) float64
CalculatePositionSize calculates optimal position size using Kelly Criterion
Kelly Criterion Formula: f* = (p * b - q) / b
Where: - f* = fraction of capital to bet (Kelly percentage) - p = probability of winning (win rate) - q = probability of losing (1 - p) - b = ratio of average win to average loss (win/loss ratio)
The formula can also be written as: f* = (W - L) / W Where W = average win, L = average loss
Kelly fraction is applied to reduce risk (typically 0.25 to 0.5 for quarter or half Kelly)
func (*KellyCalculator) CalculateStats ¶
func (kc *KellyCalculator) CalculateStats(ctx context.Context, sessionID uuid.UUID) (*TradingStats, error)
CalculateStats computes trading statistics from historical data This can be used for database-backed statistics
type MarketData ¶
type MarketData struct {
Timestamp time.Time `json:"timestamp"`
Symbol string `json:"symbol"`
CurrentPrice float64 `json:"current_price"`
OHLCV *Candlestick `json:"current_candle"`
History []*Candlestick `json:"historical_candles"`
Indicators map[string]float64 `json:"indicators,omitempty"`
Context map[string]interface{} `json:"context,omitempty"`
}
MarketData represents market data available to an agent at a point in time
type Metrics ¶
type Metrics struct {
// Returns
TotalReturn float64 `json:"total_return"` // Total profit/loss
TotalReturnPct float64 `json:"total_return_pct"` // Total return percentage
AnnualizedReturn float64 `json:"annualized_return"` // Annualized return percentage
CAGR float64 `json:"cagr"` // Compound Annual Growth Rate
// Risk metrics
MaxDrawdown float64 `json:"max_drawdown"` // Maximum drawdown in dollars
MaxDrawdownPct float64 `json:"max_drawdown_pct"` // Maximum drawdown percentage
Volatility float64 `json:"volatility"` // Standard deviation of returns
SharpeRatio float64 `json:"sharpe_ratio"` // Risk-adjusted return
SortinoRatio float64 `json:"sortino_ratio"` // Downside risk-adjusted return
CalmarRatio float64 `json:"calmar_ratio"` // CAGR / Max Drawdown
// Trade statistics
TotalTrades int `json:"total_trades"`
WinningTrades int `json:"winning_trades"`
LosingTrades int `json:"losing_trades"`
WinRate float64 `json:"win_rate"` // Percentage of winning trades
AverageWin float64 `json:"average_win"` // Average profit per winning trade
AverageLoss float64 `json:"average_loss"` // Average loss per losing trade
LargestWin float64 `json:"largest_win"`
LargestLoss float64 `json:"largest_loss"`
ProfitFactor float64 `json:"profit_factor"` // Total profit / Total loss
Expectancy float64 `json:"expectancy"` // Expected value per trade
// Time statistics
AverageHoldingTime time.Duration `json:"average_holding_time"`
MedianHoldingTime time.Duration `json:"median_holding_time"`
MaxHoldingTime time.Duration `json:"max_holding_time"`
MinHoldingTime time.Duration `json:"min_holding_time"`
// Portfolio statistics
InitialCapital float64 `json:"initial_capital"`
FinalEquity float64 `json:"final_equity"`
PeakEquity float64 `json:"peak_equity"`
EquityLow float64 `json:"equity_low"`
StartDate time.Time `json:"start_date"`
EndDate time.Time `json:"end_date"`
Duration time.Duration `json:"duration"`
}
Metrics holds all performance metrics for a backtest
func CalculateMetrics ¶
CalculateMetrics calculates all performance metrics from a backtest
type ObjectiveFunction ¶
ObjectiveFunction calculates a fitness score from backtest metrics
var ( // MaximizeSharpeRatio optimizes for risk-adjusted returns MaximizeSharpeRatio ObjectiveFunction = func(m *Metrics) float64 { return m.SharpeRatio } // MaximizeSortinoRatio optimizes for downside risk-adjusted returns MaximizeSortinoRatio ObjectiveFunction = func(m *Metrics) float64 { return m.SortinoRatio } // MaximizeCalmarRatio optimizes for return/max drawdown MaximizeCalmarRatio ObjectiveFunction = func(m *Metrics) float64 { return m.CalmarRatio } // MaximizeTotalReturn optimizes for absolute returns MaximizeTotalReturn ObjectiveFunction = func(m *Metrics) float64 { return m.TotalReturnPct } // MaximizeProfitFactor optimizes for profit/loss ratio MaximizeProfitFactor ObjectiveFunction = func(m *Metrics) float64 { return m.ProfitFactor } // MinimizeDrawdown optimizes for low drawdown MinimizeDrawdown ObjectiveFunction = func(m *Metrics) float64 { return -m.MaxDrawdownPct } // BalancedObjective combines multiple metrics BalancedObjective ObjectiveFunction = func(m *Metrics) float64 { sharpe := math.Max(0, m.SharpeRatio) winRate := m.WinRate / 100.0 calmar := math.Max(0, m.CalmarRatio) return 0.4*sharpe + 0.3*winRate + 0.3*calmar } )
Predefined objective functions
type OptimizationResult ¶
type OptimizationResult struct {
Parameters ParameterSet `json:"parameters"`
Metrics *Metrics `json:"metrics"`
Score float64 `json:"score"` // Fitness score
Rank int `json:"rank"` // Rank among all results
IsOutOfSample bool `json:"is_out_sample"` // Walk-forward out-of-sample flag
}
OptimizationResult represents the result of a parameter optimization
type OptimizationSummary ¶
type OptimizationSummary struct {
Method string `json:"method"` // grid_search, walk_forward, genetic
TotalRuns int `json:"total_runs"`
Duration time.Duration `json:"duration"`
BestResult *OptimizationResult `json:"best_result"`
TopResults []*OptimizationResult `json:"top_results"` // Top 10 results
ParameterRanges []*Parameter `json:"parameter_ranges"`
ObjectiveMetric string `json:"objective_metric"` // What we're optimizing
StartDate time.Time `json:"start_date"`
EndDate time.Time `json:"end_date"`
}
OptimizationSummary summarizes an optimization run
type Parameter ¶
type Parameter struct {
Name string `json:"name"`
Type ParamType `json:"type"` // int, float, bool, string
Min float64 `json:"min"` // For numeric types
Max float64 `json:"max"` // For numeric types
Step float64 `json:"step"` // Step size for grid search
Values []string `json:"values"` // For string/categorical types
}
Parameter represents a tunable parameter for strategy optimization
type ParameterSet ¶
type ParameterSet map[string]interface{}
ParameterSet represents a set of parameter values
func (ParameterSet) Clone ¶
func (ps ParameterSet) Clone() ParameterSet
Clone creates a deep copy of the parameter set
type Position ¶
type Position struct {
Symbol string `json:"symbol"`
Side string `json:"side"` // "LONG", "SHORT"
EntryTime time.Time `json:"entry_time"`
EntryPrice float64 `json:"entry_price"`
Quantity float64 `json:"quantity"`
CurrentPrice float64 `json:"current_price"`
UnrealizedPL float64 `json:"unrealized_pl"`
Commission float64 `json:"commission"`
}
Position represents an open trading position
type ReportGenerator ¶
type ReportGenerator struct {
// contains filtered or unexported fields
}
ReportGenerator generates HTML reports for backtest results
func NewOptimizationReportGenerator ¶
func NewOptimizationReportGenerator(engine *Engine, summary *OptimizationSummary) (*ReportGenerator, error)
NewOptimizationReportGenerator creates a report generator for optimization results
func NewReportGenerator ¶
func NewReportGenerator(engine *Engine) (*ReportGenerator, error)
NewReportGenerator creates a new report generator
func (*ReportGenerator) GenerateHTML ¶
func (r *ReportGenerator) GenerateHTML() (string, error)
GenerateHTML generates a complete HTML report
func (*ReportGenerator) SaveToFile ¶
func (r *ReportGenerator) SaveToFile(filepath string) error
SaveToFile saves the HTML report to a file
type Signal ¶
type Signal struct {
Timestamp time.Time `json:"timestamp"`
Symbol string `json:"symbol"`
Side string `json:"side"` // "BUY", "SELL", "HOLD"
Confidence float64 `json:"confidence"` // 0.0 to 1.0
Reasoning string `json:"reasoning"`
Agent string `json:"agent"` // Which agent generated this signal
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
Signal represents a trading signal from an agent
type Strategy ¶
type Strategy interface {
// Initialize is called before the backtest starts
Initialize(engine *Engine) error
// GenerateSignals generates trading signals at each time step
GenerateSignals(engine *Engine) ([]*Signal, error)
// Finalize is called after the backtest ends
Finalize(engine *Engine) error
}
Strategy is the interface that trading strategies must implement
type StrategyFactory ¶
type StrategyFactory func(params ParameterSet) (Strategy, error)
StrategyFactory creates a strategy with given parameters
type Trade ¶
type Trade struct {
ID int `json:"id"`
Timestamp time.Time `json:"timestamp"`
Symbol string `json:"symbol"`
Side string `json:"side"` // "BUY", "SELL"
Quantity float64 `json:"quantity"`
Price float64 `json:"price"`
Commission float64 `json:"commission"`
Value float64 `json:"value"` // price * quantity
Signal *Signal `json:"signal,omitempty"`
}
Trade represents an executed trade
type TradingStats ¶
type TradingStats struct {
TotalTrades int `json:"total_trades"`
WinningTrades int `json:"winning_trades"`
LosingTrades int `json:"losing_trades"`
AvgWin float64 `json:"avg_win"` // Average profit per winning trade
AvgLoss float64 `json:"avg_loss"` // Average loss per losing trade (positive value)
WinRate float64 `json:"win_rate"` // Percentage of winning trades (0.0 to 1.0)
AvgReturn float64 `json:"avg_return"` // Average return per trade
TotalProfit float64 `json:"total_profit"` // Total profit from all winning trades
TotalLoss float64 `json:"total_loss"` // Total loss from all losing trades (positive value)
LargestWin float64 `json:"largest_win"` // Largest single win
LargestLoss float64 `json:"largest_loss"` // Largest single loss (positive value)
WinLossRatio float64 `json:"win_loss_ratio"` // AvgWin / AvgLoss
}
TradingStats holds statistical data for Kelly Criterion calculation
func CalculateStatsFromTrades ¶
func CalculateStatsFromTrades(closedPositions []*ClosedPosition) *TradingStats
CalculateStatsFromTrades computes trading statistics from in-memory trades This is useful for backtesting where we don't have database access
type WalkForwardOptimizer ¶
type WalkForwardOptimizer struct {
// contains filtered or unexported fields
}
WalkForwardOptimizer performs walk-forward analysis
func NewWalkForwardOptimizer ¶
func NewWalkForwardOptimizer(factory StrategyFactory, params []*Parameter, objective ObjectiveFunction, config BacktestConfig) *WalkForwardOptimizer
NewWalkForwardOptimizer creates a new walk-forward optimizer
func (*WalkForwardOptimizer) Optimize ¶
func (opt *WalkForwardOptimizer) Optimize(ctx context.Context, data map[string][]*Candlestick) (*OptimizationSummary, error)
Optimize performs walk-forward optimization
func (*WalkForwardOptimizer) SetPeriods ¶
func (opt *WalkForwardOptimizer) SetPeriods(inSample, outSample time.Duration)
SetPeriods sets the in-sample and out-of-sample periods