import "github.com/cinar/indicator/v2/strategy"Package strategy contains the strategy functions.
This package belongs to the Indicator project. Indicator is a Golang module that supplies a variety of technical indicators, strategies, and a backtesting framework for analysis.
Copyright (c) 2021-2026 The Indicator Authors.
The source code is provided under GNU AGPLv3 License.
https://github.com/cinar/indicator
The information provided on this project is strictly for informational purposes and is not to be construed as advice or solicitation to buy or sell any security.
- Constants
- func ActionSources(strategies []Strategy, snapshots <-chan *asset.Snapshot) []<-chan Action
- func ActionSourcesWithContext(ctx context.Context, strategies []Strategy, snapshots <-chan *asset.Snapshot) []<-chan Action
- func ActionsToAnnotations(ac <-chan Action) <-chan string
- func ActionsToAnnotationsWithContext(ctx context.Context, ac <-chan Action) <-chan string
- func ComputeWithContext(ctx context.Context, s Strategy, c <-chan *asset.Snapshot) <-chan Action
- func ComputeWithOutcome(s Strategy, c <-chan *asset.Snapshot) (<-chan Action, <-chan float64)
- func ComputeWithOutcomeAndTiming(s Strategy, c <-chan *asset.Snapshot, timing ExecutionTiming) (<-chan Action, <-chan float64)
- func ComputeWithOutcomeAndTimingWithContext(ctx context.Context, s Strategy, c <-chan *asset.Snapshot, timing ExecutionTiming) (<-chan Action, <-chan float64)
- func ComputeWithOutcomeWithContext(ctx context.Context, s Strategy, c <-chan *asset.Snapshot) (<-chan Action, <-chan float64)
- func CountActions(acs []<-chan Action) (int, int, int, bool)
- func CountTransactions(ac <-chan Action) <-chan int
- func DenormalizeActions(ac <-chan Action) <-chan Action
- func DenormalizeActionsWithContext(ctx context.Context, ac <-chan Action) <-chan Action
- func NormalizeActions(ac <-chan Action) <-chan Action
- func NormalizeActionsWithContext(ctx context.Context, ac <-chan Action) <-chan Action
- func Outcome[T helper.Number](values <-chan T, actions <-chan Action) <-chan float64
- func OutcomeWithContext[T helper.Number](ctx context.Context, values <-chan T, actions <-chan Action) <-chan float64
- func SharpeRatio(outcomes <-chan float64, periodsPerYear int) float64
- func SharpeRatioWithContext(ctx context.Context, outcomes <-chan float64, periodsPerYear int) float64
- func SortinoRatio(outcomes <-chan float64, periodsPerYear int) float64
- func SortinoRatioWithContext(ctx context.Context, outcomes <-chan float64, periodsPerYear int) float64
- type Action
- type AndStrategy
- func NewAndStrategy(name string, strategies ...Strategy) *AndStrategy
- func (a *AndStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan Action
- func (a *AndStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan Action
- func (a *AndStrategy) Name() string
- func (a *AndStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
- func (a *AndStrategy) String() string
- type BuyAndHoldStrategy
- func NewBuyAndHoldStrategy() *BuyAndHoldStrategy
- func (b *BuyAndHoldStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan Action
- func (b *BuyAndHoldStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan Action
- func (*BuyAndHoldStrategy) Name() string
- func (b *BuyAndHoldStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
- func (b *BuyAndHoldStrategy) String() string
- type ExecutionTiming
- type MajorityStrategy
- func NewMajorityStrategy(name string) *MajorityStrategy
- func NewMajorityStrategyWith(name string, strategies []Strategy) *MajorityStrategy
- func (a *MajorityStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan Action
- func (a *MajorityStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan Action
- func (a *MajorityStrategy) Name() string
- func (a *MajorityStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
- func (a *MajorityStrategy) String() string
- type OrStrategy
- func NewOrStrategy(name string, strategies ...Strategy) *OrStrategy
- func (a *OrStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan Action
- func (a *OrStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan Action
- func (a *OrStrategy) Name() string
- func (a *OrStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
- func (a *OrStrategy) String() string
- type Result
- type SplitStrategy
- func NewSplitStrategy(buyStrategy, sellStrategy Strategy) *SplitStrategy
- func (s *SplitStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan Action
- func (s *SplitStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan Action
- func (s *SplitStrategy) Name() string
- func (s *SplitStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
- func (s *SplitStrategy) String() string
- type Strategy
- type WithContext
const (
// DefaultSharpeRatioPeriodsPerYear is the default number of return periods in a year, matching
// the approximate number of trading days used to annualize a Sharpe Ratio computed from daily
// outcomes.
DefaultSharpeRatioPeriodsPerYear = 252
)const (
// DefaultSortinoRatioPeriodsPerYear is the default number of return periods in a year, matching
// the approximate number of trading days used to annualize a Sortino Ratio computed from daily
// outcomes.
DefaultSortinoRatioPeriodsPerYear = 252
)func ActionSources
func ActionSources(strategies []Strategy, snapshots <-chan *asset.Snapshot) []<-chan ActionActionSources creates a slice of action channels, one for each strategy, where each channel emits actions computed by its corresponding strategy based on snapshots from the provided snapshot channel.
Deprecated: Use ActionSourcesWithContext instead.
func ActionSourcesWithContext(ctx context.Context, strategies []Strategy, snapshots <-chan *asset.Snapshot) []<-chan ActionActionSourcesWithContext creates a slice of action channels, one for each strategy, where each channel emits actions computed by its corresponding strategy based on snapshots from the provided snapshot channel, supporting context cancellation.
func ActionsToAnnotations
func ActionsToAnnotations(ac <-chan Action) <-chan stringActionsToAnnotations takes a channel of action recommendations and returns a new channel containing corresponding annotations for those actions.
Deprecated: Use ActionsToAnnotationsWithContext instead.
func ActionsToAnnotationsWithContext(ctx context.Context, ac <-chan Action) <-chan stringActionsToAnnotationsWithContext takes a channel of action recommendations and returns a new channel containing corresponding annotations for those actions, supporting context cancellation.
func ComputeWithContext
func ComputeWithContext(ctx context.Context, s Strategy, c <-chan *asset.Snapshot) <-chan ActionComputeWithContext processes snapshots with a strategy using context.
func ComputeWithOutcome
func ComputeWithOutcome(s Strategy, c <-chan *asset.Snapshot) (<-chan Action, <-chan float64)ComputeWithOutcome uses the given strategy to processes the provided asset snapshots and generates a stream of actionable recommendations and outcomes.
Deprecated: Use ComputeWithOutcomeWithContext instead.
func ComputeWithOutcomeAndTiming(s Strategy, c <-chan *asset.Snapshot, timing ExecutionTiming) (<-chan Action, <-chan float64)ComputeWithOutcomeAndTiming uses the given strategy to process the provided asset snapshots and generates a stream of actionable recommendations and outcomes, using the given ExecutionTiming to decide which price a simulated trade executes at.
See ComputeWithOutcomeAndTimingWithContext for details, including the note on the outcomes channel being shorter than the actions channel when timing is NextOpen or NextClose.
func ComputeWithOutcomeAndTimingWithContext(ctx context.Context, s Strategy, c <-chan *asset.Snapshot, timing ExecutionTiming) (<-chan Action, <-chan float64)ComputeWithOutcomeAndTimingWithContext uses the given strategy to process the provided asset snapshots and generates a stream of actionable recommendations and outcomes, using the given ExecutionTiming to decide which price a simulated trade executes at, supporting context cancellation.
With AtClose, this behaves identically to ComputeWithOutcomeWithContext: each action is paired with the closing price of the same bar it was computed from.
With NextOpen or NextClose, each action is instead paired with the opening or closing price of the following bar. As a result, the returned outcomes channel yields one fewer value than the returned actions channel, since there is no following bar for the last action. Callers that need the actions and outcomes channels aligned position-for-position (for example, to build a report column) must account for this offset themselves, the same way many strategies already skip-align channels of differing lengths. Callers only interested in the final/aggregate outcome (for example, via helper.Last(outcomes, 1)) are unaffected either way.
func ComputeWithOutcomeWithContext(ctx context.Context, s Strategy, c <-chan *asset.Snapshot) (<-chan Action, <-chan float64)ComputeWithOutcomeWithContext uses the given strategy to processes the provided asset snapshots and generates a stream of actionable recommendations and outcomes, supporting context cancellation.
func CountActions
func CountActions(acs []<-chan Action) (int, int, int, bool)CountActions taken a slice of Action channels, and counts them by their type.
func CountTransactions
func CountTransactions(ac <-chan Action) <-chan intCountTransactions counts the number of recommended Buy and Sell actions.
func DenormalizeActions
func DenormalizeActions(ac <-chan Action) <-chan ActionDenormalizeActions simplifies the representation of the action sequence.
Deprecated: Use DenormalizeActionsWithContext instead.
func DenormalizeActionsWithContext(ctx context.Context, ac <-chan Action) <-chan ActionDenormalizeActionsWithContext simplifies the representation of the action sequence and facilitates subsequent processing by transforming the given channel of actions, supporting context cancellation.
func NormalizeActions
func NormalizeActions(ac <-chan Action) <-chan ActionNormalizeActions transforms the given channel of actions to ensure a consistent and predictable sequence.
Deprecated: Use NormalizeActionsWithContext instead.
func NormalizeActionsWithContext(ctx context.Context, ac <-chan Action) <-chan ActionNormalizeActionsWithContext transforms the given channel of actions to ensure a consistent and predictable sequence, supporting context cancellation.
func Outcome
func Outcome[T helper.Number](values <-chan T, actions <-chan Action) <-chan float64Outcome simulates the potential result of executing the given actions based on the provided values.
See OutcomeWithContext for details on the same-bar/"at close" execution assumption.
Deprecated: Use OutcomeWithContext instead.
func OutcomeWithContext
func OutcomeWithContext[T helper.Number](ctx context.Context, values <-chan T, actions <-chan Action) <-chan float64OutcomeWithContext simulates the potential result of executing the given actions based on the provided values, supporting context cancellation.
The values and actions channels are paired positionally: the value at position i is assumed to be the execution price for the action at position i. Callers that pass same-bar closing prices are therefore simulating same-bar/"at close" execution, i.e. the trade is assumed to fill at the very same closing price that produced the signal. This is unrealistic (a signal cannot be acted upon before the bar that generated it has been observed) and tends to overstate backtest performance. Callers who want the more realistic assumption of executing on the next bar's open or close should use ComputeWithOutcomeAndTimingWithContext (or ComputeWithOutcomeAndTiming) with ExecutionTiming NextOpen or NextClose instead of constructing the values channel directly.
func SharpeRatio
func SharpeRatio(outcomes <-chan float64, periodsPerYear int) float64SharpeRatio wraps SharpeRatioWithContext for backwards compatibility.
Deprecated: Use SharpeRatioWithContext instead.
func SharpeRatioWithContext(ctx context.Context, outcomes <-chan float64, periodsPerYear int) float64SharpeRatioWithContext computes the annualized Sharpe Ratio for the given stream of cumulative outcome values, as produced by OutcomeWithContext, supporting context cancellation.
Sharpe = Mean(periodReturns) / StdDev(periodReturns) * Sqrt(periodsPerYear)
The risk-free rate is assumed to be zero. The outcomes channel is assumed to hold one cumulative return value per trading period (for example, one per daily snapshot), which is exactly what OutcomeWithContext produces. Per-period returns are derived from the change in the underlying equity curve (1 + outcome) between consecutive outcomes.
Fewer than two outcome values, or a return series with zero (or floating-point-noise-level) variance, such as a strategy that never trades, yields a Sharpe Ratio of zero rather than dividing by a near-zero standard deviation.
func SortinoRatio
func SortinoRatio(outcomes <-chan float64, periodsPerYear int) float64SortinoRatio wraps SortinoRatioWithContext for backwards compatibility.
Deprecated: Use SortinoRatioWithContext instead.
func SortinoRatioWithContext(ctx context.Context, outcomes <-chan float64, periodsPerYear int) float64SortinoRatioWithContext computes the annualized Sortino Ratio for the given stream of cumulative outcome values, as produced by OutcomeWithContext, supporting context cancellation.
Sortino = Mean(periodReturns) / DownsideDeviation(periodReturns) * Sqrt(periodsPerYear)
Unlike the Sharpe Ratio, which divides by the standard deviation of all returns, the Sortino Ratio divides by the downside deviation: the root-mean-square of only the shortfall below a minimum acceptable return (assumed to be zero here), with periods at or above that return contributing zero. Two return series with identical upside volatility but different downside volatility therefore yield different Sortino Ratios, even when their Sharpe Ratios are equal.
The outcomes channel is assumed to hold one cumulative return value per trading period (for example, one per daily snapshot), which is exactly what OutcomeWithContext produces. Per-period returns are derived from the change in the underlying equity curve (1 + outcome) between consecutive outcomes.
Fewer than two outcome values, or a return series with zero (or floating-point-noise-level) downside deviation, such as a strategy whose returns never fall below the minimum acceptable return, yields a Sortino Ratio of zero rather than dividing by a near-zero downside deviation.
type Action
Action represents the different action categories that a strategy can recommend.
type Action intconst (
// Hold suggests maintaining the current position and not
// taking any actions on the asset.
Hold Action = 0
// Sell suggests disposing of the asset and exiting the current position.
// This recommendation typically indicates that the strategy believes the
// asset's price has reached its peak or is likely to decline.
Sell Action = -1
// Buy suggests acquiring the asset and entering a new position. This
// recommendation usually implies that the strategy believes the
// asset's price is undervalued.
Buy Action = 1
)func (Action) Annotation
func (a Action) Annotation() stringAnnotation returns a single character string representing the recommended action. It returns "S" for Sell, "B" for Buy, and an empty string for Hold.
type AndStrategy
AndStrategy combines multiple strategies and emits actionable recommendations when **all** strategies in the group **reach the same actionable conclusion**. This can be a conservative approach, potentially delaying recommendations until full consensus is reached.
type AndStrategy struct {
// Strategies are the group of strategies that will be consulted to make an actionable recommendation.
Strategies []Strategy
// contains filtered or unexported fields
}func NewAndStrategy
func NewAndStrategy(name string, strategies ...Strategy) *AndStrategyNewAndStrategy function initializes an empty and strategies group with the given name.
func (*AndStrategy) Compute
func (a *AndStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan ActionCompute wraps ComputeWithContext for backwards compatibility.
Deprecated: Use ComputeWithContext instead.
func (*AndStrategy) ComputeWithContext
func (a *AndStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan ActionComputeWithContext processes the provided asset snapshots and generates an illustrative stream of actions.
func (*AndStrategy) Name
func (a *AndStrategy) Name() stringName returns the name of the example strategy.
func (*AndStrategy) Report
func (a *AndStrategy) Report(c <-chan *asset.Snapshot) *helper.ReportReport processes the provided asset snapshots and generates an illustrative report annotated with example actions.
func (*AndStrategy) String
func (a *AndStrategy) String() stringString is the string representation of the AndStrategy.
type BuyAndHoldStrategy
BuyAndHoldStrategy demonstrates a baseline buy-and-hold strategy for illustrative and benchmarking purposes.
type BuyAndHoldStrategy struct {
}func NewBuyAndHoldStrategy() *BuyAndHoldStrategyNewBuyAndHoldStrategy initializes an example BuyAndHoldStrategy instance with default parameters.
func (*BuyAndHoldStrategy) Compute
func (b *BuyAndHoldStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan ActionCompute wraps ComputeWithContext for backwards compatibility.
Deprecated: Use ComputeWithContext instead.
func (*BuyAndHoldStrategy) ComputeWithContext
func (b *BuyAndHoldStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan ActionComputeWithContext processes the provided asset snapshots and generates an illustrative stream of actions.
func (*BuyAndHoldStrategy) Name
func (*BuyAndHoldStrategy) Name() stringName returns the name of the example strategy.
func (*BuyAndHoldStrategy) Report
func (b *BuyAndHoldStrategy) Report(c <-chan *asset.Snapshot) *helper.ReportReport processes the provided asset snapshots and generates an illustrative report annotated with example actions.
func (*BuyAndHoldStrategy) String
func (b *BuyAndHoldStrategy) String() stringString is the string representation of the BuyAndHoldStrategy.
type ExecutionTiming
ExecutionTiming represents when a simulated trade executes relative to the bar its action was computed from.
type ExecutionTiming intconst (
// AtClose executes at the same bar's closing price. This is the existing default behavior used by
// OutcomeWithContext and ComputeWithOutcomeWithContext, and assumes the trade fills at the very
// close that produced the signal.
AtClose ExecutionTiming = iota
// NextOpen executes at the opening price of the bar immediately following the signal. This is a
// more realistic assumption for strategies that can only act after a bar has fully closed.
NextOpen
// NextClose executes at the closing price of the bar immediately following the signal.
NextClose
)func (ExecutionTiming) String
func (e ExecutionTiming) String() stringString returns the string representation of the ExecutionTiming.
type MajorityStrategy
MajorityStrategy emits actionable recommendations aligned with what the strategies in the group recommends.
type MajorityStrategy struct {
// Strategies are the group of strategies that will be consulted to make an actionable recommendation.
Strategies []Strategy
// contains filtered or unexported fields
}func NewMajorityStrategy
func NewMajorityStrategy(name string) *MajorityStrategyNewMajorityStrategy function initializes an empty majority strategies group with the given name.
func NewMajorityStrategyWith(name string, strategies []Strategy) *MajorityStrategyNewMajorityStrategyWith function initializes a majority strategies group with the given name and strategies.
func (*MajorityStrategy) Compute
func (a *MajorityStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan ActionCompute wraps ComputeWithContext for backwards compatibility.
Deprecated: Use ComputeWithContext instead.
func (*MajorityStrategy) ComputeWithContext
func (a *MajorityStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan ActionComputeWithContext processes the provided asset snapshots and generates an illustrative stream of actions.
func (*MajorityStrategy) Name
func (a *MajorityStrategy) Name() stringName returns the name of the example strategy.
func (*MajorityStrategy) Report
func (a *MajorityStrategy) Report(c <-chan *asset.Snapshot) *helper.ReportReport processes the provided asset snapshots and generates an illustrative report annotated with example actions.
func (*MajorityStrategy) String
func (a *MajorityStrategy) String() stringString is the string representation of the MajorityStrategy.
type OrStrategy
OrStrategy emits actionable recommendations when **at least one** strategy in the group recommends an action **without any conflicting recommendations** from other strategies.
type OrStrategy struct {
// Strategies are the group of strategies that will be consulted to make an actionable recommendation.
Strategies []Strategy
// contains filtered or unexported fields
}func NewOrStrategy
func NewOrStrategy(name string, strategies ...Strategy) *OrStrategyNewOrStrategy function initializes an empty or strategies group with the given name.
func (*OrStrategy) Compute
func (a *OrStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan ActionCompute wraps ComputeWithContext for backwards compatibility.
Deprecated: Use ComputeWithContext instead.
func (*OrStrategy) ComputeWithContext
func (a *OrStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan ActionComputeWithContext processes the provided asset snapshots and generates an illustrative stream of actions.
func (*OrStrategy) Name
func (a *OrStrategy) Name() stringName returns the name of the example strategy.
func (*OrStrategy) Report
func (a *OrStrategy) Report(c <-chan *asset.Snapshot) *helper.ReportReport processes the provided asset snapshots and generates an illustrative report annotated with example actions.
func (*OrStrategy) String
func (a *OrStrategy) String() stringString is the string representation of the OrStrategy.
type Result
Result is only used inside the test cases to facilitate the comparison between the actual and expected strategy results.
type Result struct {
Action Action
}type SplitStrategy
SplitStrategy leverages two separate strategies. It utilizes the first strategy to identify potential Buy opportunities, and the second strategy to identify potential Sell opportunities. When there is a conflicting recommendation, returns Hold.
type SplitStrategy struct {
// BuyStrategy is used to identify potential Buy opportunities.
BuyStrategy Strategy
// SellStrategy is used to identify potential Sell opportunities.
SellStrategy Strategy
}func NewSplitStrategy
func NewSplitStrategy(buyStrategy, sellStrategy Strategy) *SplitStrategyNewSplitStrategy initializes an example SplitStrategy instance with default parameters.
func (*SplitStrategy) Compute
func (s *SplitStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan ActionCompute wraps ComputeWithContext for backwards compatibility.
Deprecated: Use ComputeWithContext instead.
func (*SplitStrategy) ComputeWithContext
func (s *SplitStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan ActionComputeWithContext processes the provided asset snapshots and generates an illustrative stream of actions.
func (*SplitStrategy) Name
func (s *SplitStrategy) Name() stringName returns the name of the example strategy.
func (*SplitStrategy) Report
func (s *SplitStrategy) Report(c <-chan *asset.Snapshot) *helper.ReportReport processes the provided asset snapshots and generates an illustrative report annotated with example actions.
func (*SplitStrategy) String
func (s *SplitStrategy) String() stringString is the string representation of the SplitStrategy.
type Strategy
Strategy defines a shared interface for trading strategies.
type Strategy interface {
// Name returns the name of the example strategy.
Name() string
// Compute processes the provided asset snapshots and generates a
// stream of actionable recommendations.
Compute(snapshots <-chan *asset.Snapshot) <-chan Action
// Report processes the provided asset snapshots and generates a
// report annotated with the recommended actions.
Report(snapshots <-chan *asset.Snapshot) *helper.Report
}func AllAndStrategies
func AllAndStrategies(strategies []Strategy) []StrategyAllAndStrategies performs a cartesian product operation on the given strategies, resulting in a collection containing all and strategies formed by combining two strategies together.
func AllSplitStrategies
func AllSplitStrategies(strategies []Strategy) []StrategyAllSplitStrategies performs a cartesian product operation on the given strategies, resulting in a collection containing all split strategies formed by combining individual buy and sell strategies.
func AllStrategies
func AllStrategies() []StrategyAllStrategies returns a slice containing references to all available base strategies.
type WithContext
WithContext defines a shared interface for trading strategies supporting context-aware computations.
type WithContext interface {
Strategy
ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan Action
}Generated by gomarkdoc