diff --git a/README.md b/README.md
index c8973d4d..24131a4b 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ Indicator is a Golang module that provides a rich set of technical analysis indi
- **Enhanced Code Quality:** A complete rewrite was undertaken to achieve and maintain at least 90% code coverage.
- **Improved Testability:** Each indicator and strategy have dedicated test data in CSV format for easier validation.
-- **Streamlined Data Handling:** The library was rewritten to operate on data streams (Go channels) for both inputs and outputs. If you prefer using slices, helper functions like [helper.SliceToChan](helper/README.md#func-slicetochan) and [helper.ChanToSlice](helper/README.md#func-chantoslice) are available. Alternatively, you can still use the [v1 version](https://github.com/cinar/indicator/tree/v1).
+- **Streamlined Data Handling:** The library was rewritten to operate on data streams (Go channels) for both inputs and outputs. If you prefer using slices, helper functions like [helper.SliceToChan](helper/README.md#SliceToChan) and [helper.ChanToSlice](helper/README.md#ChanToSlice) are available. Alternatively, you can still use the [v1 version](https://github.com/cinar/indicator/tree/v1).
- **Configurable Indicators and Strategies:** All indicators and strategies were designed to be fully configurable with no preset values.
- **Generics Support:** The library leverages Golang generics to support various numeric data formats.
- **MCP Support:** MCP (Multi-Client Protocol Server) support is integrated into the library, facilitating its use with various AI tools.
@@ -27,96 +27,95 @@ The following list of indicators are currently supported by this package:
### ๐ Trend Indicators
-- [Absolute Price Oscillator (APO)](trend/README.md#type-apo)
-- [Aroon Indicator](trend/README.md#type-aroon)
-- [Balance of Power (BoP)](trend/README.md#type-bop)
-- [Chande Forecast Oscillator (CFO)](trend/README.md#cfo)
-- [Commodity Channel Index (CCI)](trend/README.md#type-cci)
-- [Envelope](trend/README.md#type-envelope)
-- [Hull Moving Average (HMA)](trend/README.md#type-hma)
-- [Detrended Price Oscillator (DPO)](trend/README.md#type-dpo)
-- [Double Exponential Moving Average (DEMA)](trend/README.md#type-dema)
-- [Exponential Moving Average (EMA)](trend/README.md#type-ema)
-- [Kaufman's Adaptive Moving Average (KAMA)](trend/README.md#type-kama)
-- [Know Sure Thing (KST)](trend/README.md#type-kst)
-- [Mass Index (MI)](trend/README.md#type-massindex)
-- [McGinley Dynamic](trend/README.md#type-mcginleydynamic)
-- [Moving Average Convergence Divergence (MACD)](trend/README.md#type-macd)
-- [Moving Least Square (MLS)](trend/README.md#type-mls)
-- [Moving Linear Regression (MLR)](trend/README.md#type-mlr)
-- [Moving Max](trend/README.md#type-movingmax)
-- [Moving Min](trend/README.md#type-movingmin)
-- [Moving Sum](trend/README.md#type-movingsum)
-- Parabolic SAR
-- [Random Index (KDJ)](trend/README.md#type-kdj)
-- [Stochastic](trend/README.md#type-stochastic)
-- [Slow Stochastic](trend/README.md#type-slowstochastic)
-- [Schaff Trend Cycle (STC)](trend/README.md#type-stc)
-- [Rolling Moving Average (RMA)](trend/README.md#type-rma)
-- [Simple Moving Average (SMA)](trend/README.md#type-sma)
-- [Since Change](helper/README.md#func-since)
-- [Smoothed Moving Average (SMMA)](trend/README.md#type-smma)
-- [Triple Exponential Moving Average (TEMA)](trend/README.md#type-tema)
-- [Triangular Moving Average (TRIMA)](trend/README.md#type-trima)
-- [Triple Exponential Average (TRIX)](trend/README.md#type-trix)
-- [True Strength Index (TSI)](trend/README.md#type-tsi)
+- [Absolute Price Oscillator (APO)](trend/README.md#Apo)
+- [Alligator Indicator](trend/README.md#Alligator)
+- [Aroon Indicator](trend/README.md#Aroon)
+- [Balance of Power (BoP)](trend/README.md#Bop)
+- [Chande Forecast Oscillator (CFO)](trend/README.md#Cfo)
+- [Commodity Channel Index (CCI)](trend/README.md#Cci)
+- [Envelope](trend/README.md#Envelope)
+- [Hull Moving Average (HMA)](trend/README.md#Hma)
+- [Detrended Price Oscillator (DPO)](trend/README.md#Dpo)
+- [Double Exponential Moving Average (DEMA)](trend/README.md#Dema)
+- [Exponential Moving Average (EMA)](trend/README.md#Ema)
+- [Kaufman's Adaptive Moving Average (KAMA)](trend/README.md#Kama)
+- [Know Sure Thing (KST)](trend/README.md#Kst)
+- [Mass Index (MI)](trend/README.md#MassIndex)
+- [McGinley Dynamic](trend/README.md#McGinleyDynamic)
+- [Moving Average Convergence Divergence (MACD)](trend/README.md#Macd)
+- [Moving Least Square (MLS)](trend/README.md#Mls)
+- [Moving Linear Regression (MLR)](trend/README.md#Mlr)
+- [Moving Max](trend/README.md#MovingMax)
+- [Moving Min](trend/README.md#MovingMin)
+- [Moving Sum](trend/README.md#MovingSum)
+- [Pivot Point](trend/README.md#PivotPoint)
+- [Random Index (KDJ)](trend/README.md#Kdj)
+- [Stochastic](trend/README.md#Stochastic)
+- [Slow Stochastic](trend/README.md#SlowStochastic)
+- [Schaff Trend Cycle (STC)](trend/README.md#Stc)
+- [Rolling Moving Average (RMA)](trend/README.md#Rma)
+- [Simple Moving Average (SMA)](trend/README.md#Sma)
+- [Since Change](helper/README.md#Since)
+- [Smoothed Moving Average (SMMA)](trend/README.md#Smma)
+- [Triple Exponential Moving Average (TEMA)](trend/README.md#Tema)
+- [Triangular Moving Average (TRIMA)](trend/README.md#Trima)
+- [Triple Exponential Average (TRIX)](trend/README.md#Trix)
+- [True Strength Index (TSI)](trend/README.md#Tsi)
- [Tillson T3](trend/README.md#T3)
-- [Typical Price](trend/README.md#type-typicalprice)
-- [Volume Weighted Moving Average (VWMA)](trend/README.md#type-vwma)
-- Vortex Indicator
-- [Weighted Close](trend/README.md#type-weightedclose)
-- [Weighted Moving Average (WMA)](trend/README.md#type-wma)
+- [Typical Price](trend/README.md#TypicalPrice)
+- [Volume Weighted Moving Average (VWMA)](trend/README.md#Vwma)
+- [Weighted Close](trend/README.md#WeightedClose)
+- [Weighted Moving Average (WMA)](trend/README.md#Wma)
### ๐ Momentum Indicators
-- [Awesome Oscillator](momentum/README.md#type-awesomeoscillator)
-- [Chaikin Oscillator](momentum/README.md#type-chaikinoscillator)
-- [Connors RSI](momentum/README.md#type-connorsrsi)
-- [Coppock Curve](momentum/README.md#type-coppockcurve)
+- [Awesome Oscillator](momentum/README.md#AwesomeOscillator)
+- [Chaikin Oscillator](momentum/README.md#ChaikinOscillator)
+- [Connors RSI](momentum/README.md#ConnorsRsi)
+- [Coppock Curve](momentum/README.md#CoppockCurve)
- [Elder-Ray Index](momentum/README.md#ElderRay)
- [Fisher Transform](momentum/README.md#Fisher)
-- [Ichimoku Cloud](momentum/README.md#type-ichimokucloud)
-- [Percentage Price Oscillator (PPO)](momentum/README.md#type-ppo)
-- [Percentage Volume Oscillator (PVO)](momentum/README.md#type-pvo)
+- [Ichimoku Cloud](momentum/README.md#IchimokuCloud)
+- [Percentage Price Oscillator (PPO)](momentum/README.md#Ppo)
+- [Percentage Volume Oscillator (PVO)](momentum/README.md#Pvo)
- [Martin Pring's Special K](momentum/README.md#PringsSpecialK)
-- [Relative Strength Index (RSI)](momentum/README.md#type-rsi)
+- [Relative Strength Index (RSI)](momentum/README.md#Rsi)
- [Relative Vigor Index (RVI)](momentum/README.md#Rvi)
-- [Qstick](momentum/README.md#type-qstick)
-- [Stochastic Oscillator](momentum/README.md#type-stochasticoscillator)
-- [Stochastic RSI](momentum/README.md#type-stochasticrsi)
-- [TD Sequential](momentum/README.md#type-tdsequential)
-- [Williams R](momentum/README.md#type-williamsr)
+- [Qstick](momentum/README.md#Qstick)
+- [Stochastic Oscillator](momentum/README.md#StochasticOscillator)
+- [Stochastic RSI](momentum/README.md#StochasticRsi)
+- [TD Sequential](momentum/README.md#TdSequential)
### ๐ข Volatility Indicators
-- [%B](volatility/README.md#type-percentb)
-- [Acceleration Bands](volatility/README.md#type-accelerationbands)
-- [Actual True Range (ATR)](volatility/README.md#type-atr)
-- [Bollinger Band Width](volatility/README.md#type-bollingerbandwidth)
-- [Bollinger Bands](volatility/README.md#type-bollingerbands)
-- [Chandelier Exit](volatility/README.md#type-chandelierexit)
-- [Choppiness Index (CHOP)](volatility/README.md#type-chop)
-- [Donchian Channel (DC)](volatility/README.md#type-donchianchannel)
-- [Keltner Channel (KC)](volatility/README.md#type-keltnerchannel)
-- [Moving Standard Deviation (Std)](volatility/README.md#type-movingstd)
-- [Projection Oscillator (PO)](volatility/README.md#type-po)
-- [Super Trend](volatility/README.md#type-supertrend)
-- [Ulcer Index (UI)](volatility/README.md#type-ulcerindex)
+- [Percent B](volatility/README.md#PercentB)
+- [Acceleration Bands](volatility/README.md#AccelerationBands)
+- [Average True Range (ATR)](volatility/README.md#Atr)
+- [Bollinger Band Width](volatility/README.md#BollingerBandWidth)
+- [Bollinger Bands](volatility/README.md#BollingerBands)
+- [Chandelier Exit](volatility/README.md#ChandelierExit)
+- [Choppiness Index (CHOP)](volatility/README.md#Chop)
+- [Donchian Channel (DC)](volatility/README.md#DonchianChannel)
+- [Keltner Channel (KC)](volatility/README.md#KeltnerChannel)
+- [Moving Standard Deviation (Std)](volatility/README.md#MovingStd)
+- [Projection Oscillator (PO)](volatility/README.md#Po)
+- [Super Trend](volatility/README.md#SuperTrend)
+- [Ulcer Index (UI)](volatility/README.md#UlcerIndex)
### ๐ข Volume Indicators
-- [Accumulation/Distribution (A/D)](volume/README.md#type-ad)
-- [Chaikin Money Flow (CMF)](volume/README.md#type-cmf)
-- [Ease of Movement (EMV)](volume/README.md#type-emv)
-- [Force Index (FI)](volume/README.md#type-fi)
-- [Klinger Volume Oscillator (KVO)](volume/README.md#type-kvo)
-- [Money Flow Index (MFI)](volume/README.md#type-mfi)
-- [Money Flow Multiplier (MFM)](volume/README.md#type-mfm)
-- [Money Flow Volume (MFV)](volume/README.md#type-mfv)
-- [Negative Volume Index (NVI)](volume/README.md#type-nvi)
-- [On-Balance Volume (OBV)](volume/README.md#type-obv)
-- [Volume Price Trend (VPT)](volume/README.md#type-vpt)
-- [Volume Weighted Average Price (VWAP)](volume/README.md#type-vwap)
+- [Accumulation/Distribution (A/D)](volume/README.md#Ad)
+- [Chaikin Money Flow (CMF)](volume/README.md#Cmf)
+- [Ease of Movement (EMV)](volume/README.md#Emv)
+- [Force Index (FI)](volume/README.md#Fi)
+- [Klinger Volume Oscillator (KVO)](volume/README.md#Kvo)
+- [Money Flow Index (MFI)](volume/README.md#Mfi)
+- [Money Flow Multiplier (MFM)](volume/README.md#Mfm)
+- [Money Flow Volume (MFV)](volume/README.md#Mfv)
+- [Negative Volume Index (NVI)](volume/README.md#Nvi)
+- [On-Balance Volume (OBV)](volume/README.md#Obv)
+- [Volume Price Trend (VPT)](volume/README.md#Vpt)
+- [Volume Weighted Average Price (VWAP)](volume/README.md#Vwap)
### ๐ฐ Asset Valuation
- [Future Value (FV)](valuation/README.md#Fv)
@@ -134,79 +133,81 @@ The following list of strategies are currently supported by this package:
### ๐ Trend Strategies
-- [Alligator Strategy](strategy/trend/README.md#type-alligatorstrategy)
-- [Absolute Price Oscillator (APO) Strategy](strategy/trend/README.md#type-apostrategy)
-- [Aroon Strategy](strategy/trend/README.md#type-aroonstrategy)
-- [Balance of Power (BoP) Strategy](strategy/trend/README.md#type-bopstrategy)
-- [Chande Forecast Oscillator Strategy](strategy/trend/README.md#cfostrategy)
-- [Commodity Channel Index (CCI) Strategy](strategy/trend/README.md#type-ccistrategy)
-- [Double Exponential Moving Average (DEMA) Strategy](strategy/trend/README.md#type-demastrategy)
-- [Envelope Strategy](strategy/trend/README.md#type-envelope)
-- [Golden Cross Strategy](strategy/trend/README.md#type-goldencrossstrategy)
-- [Kaufman's Adaptive Moving Average (KAMA) Strategy](strategy/trend/README.md#type-kamastrategy)
-- [Moving Average Convergence Divergence (MACD) Strategy](strategy/trend/README.md#type-macdstrategy)
-- [Qstick Strategy](strategy/trend/README.md#type-qstickstrategy)
-- [Random Index (KDJ) Strategy](strategy/trend/README.md#type-kdjstrategy)
-- [Smoothed Moving Average (SMMA) Strategy](strategy/trend/README.md#type-smmastrategy)
-- [Triangular Moving Average (TRIMA) Strategy](strategy/trend/README.md#type-trimastrategy)
-- [Triple Exponential Average (TRIX) Strategy](strategy/trend/README.md#type-trixstrategy)
-- [Triple Moving Average Crossover Strategy](strategy/trend/README.md#type-triplemovingaveragecrossoverstrategy)
-- [True Strength Index (TSI) Strategy](strategy/trend/README.md#type-tsistrategy)
-- [Volume Weighted Moving Average (VWMA) Strategy](strategy/trend/README.md#type-vwmastrategy)
-- [Weighted Close Strategy](strategy/trend/README.md#type-weightedclosestrategy)
+- [Alligator Strategy](strategy/trend/README.md#AlligatorStrategy)
+- [Absolute Price Oscillator (APO) Strategy](strategy/trend/README.md#ApoStrategy)
+- [Aroon Strategy](strategy/trend/README.md#AroonStrategy)
+- [Balance of Power (BoP) Strategy](strategy/trend/README.md#BopStrategy)
+- [Chande Forecast Oscillator Strategy](strategy/trend/README.md#CfoStrategy)
+- [Commodity Channel Index (CCI) Strategy](strategy/trend/README.md#CciStrategy)
+- [Double Exponential Moving Average (DEMA) Strategy](strategy/trend/README.md#DemaStrategy)
+- [Envelope Strategy](strategy/trend/README.md#EnvelopeStrategy)
+- [Golden Cross Strategy](strategy/trend/README.md#GoldenCrossStrategy)
+- [Kaufman's Adaptive Moving Average (KAMA) Strategy](strategy/trend/README.md#KamaStrategy)
+- [Moving Average Convergence Divergence (MACD) Strategy](strategy/trend/README.md#MacdStrategy)
+- [Qstick Strategy](strategy/trend/README.md#QstickStrategy)
+- [Random Index (KDJ) Strategy](strategy/trend/README.md#KdjStrategy)
+- [Smoothed Moving Average (SMMA) Strategy](strategy/trend/README.md#SmmaStrategy)
+- [Triangular Moving Average (TRIMA) Strategy](strategy/trend/README.md#TrimaStrategy)
+- [Triple Exponential Average (TRIX) Strategy](strategy/trend/README.md#TrixStrategy)
+- [Triple Moving Average Crossover Strategy](strategy/trend/README.md#TripleMovingAverageCrossoverStrategy)
+- [True Strength Index (TSI) Strategy](strategy/trend/README.md#TsiStrategy)
+- [Volume Weighted Moving Average (VWMA) Strategy](strategy/trend/README.md#VwmaStrategy)
+- [Weighted Close Strategy](strategy/trend/README.md#WeightedCloseStrategy)
### ๐ Momentum Strategies
-- [Awesome Oscillator Strategy](strategy/momentum/README.md#type-awesomeoscillatorstrategy)
-- [RSI Strategy](strategy/momentum/README.md#type-rsistrategy)
-- [Stochastic RSI Strategy](strategy/momentum/README.md#type-stochasticrsistrategy)
-- Williams R Strategy
+- [Awesome Oscillator Strategy](strategy/momentum/README.md#AwesomeOscillatorStrategy)
+- [Ichimoku Cloud Strategy](strategy/momentum/README.md#IchimokuCloudStrategy)
+- [RSI Strategy](strategy/momentum/README.md#RsiStrategy)
+- [Stochastic RSI Strategy](strategy/momentum/README.md#StochasticRsiStrategy)
+- [Triple RSI Strategy](strategy/momentum/README.md#TripleRsiStrategy)
### ๐ข Volatility Strategies
-- [Bollinger Bands Strategy](strategy/volatility/README.md#type-bollingerbandsstrategy)
-- Projection Oscillator Strategy
+- [Bollinger Bands Strategy](strategy/volatility/README.md#BollingerBandsStrategy)
+- [Super Trend Strategy](strategy/volatility/README.md#SuperTrendStrategy)
### ๐ข Volume Strategies
-- [Chaikin Money Flow Strategy](strategy/volume/README.md#type-chaikinmoneyflowstrategy)
-- [Ease of Movement Strategy](strategy/volume/README.md#type-easeofmovementstrategy)
-- [Force Index Strategy](strategy/volume/README.md#type-forceindexstrategy)
-- [Money Flow Index Strategy](strategy/volume/README.md#type-moneyflowindexstrategy)
-- [Negative Volume Index Strategy](strategy/volume/README.md#type-negativevolumeindexstrategy)
-- [Weighted Average Price Strategy](strategy/volume/README.md#type-weightedaveragepricestrategy)
+- [Chaikin Money Flow Strategy](strategy/volume/README.md#ChaikinMoneyFlowStrategy)
+- [Ease of Movement Strategy](strategy/volume/README.md#EaseOfMovementStrategy)
+- [Force Index Strategy](strategy/volume/README.md#ForceIndexStrategy)
+- [Money Flow Index Strategy](strategy/volume/README.md#MoneyFlowIndexStrategy)
+- [Negative Volume Index Strategy](strategy/volume/README.md#NegativeVolumeIndexStrategy)
+- [Percent Band and MFI Strategy](strategy/volume/README.md#PercentBandMFIStrategy)
+- [Weighted Average Price Strategy](strategy/volume/README.md#WeightedAveragePriceStrategy)
### ๐งช Compound Strategies
Compound strategies merge multiple strategies to produce integrated recommendations. They combine individual strategies' recommendations using various decision-making logic.
-- [All Strategy](strategy/README.md#type-allstrategy)
-- [Majority Strategy](strategy/README.md#type-majoritystrategy)
-- [MACD-RSI Strategy](strategy/compound/README.md#type-macdrsistrategy)
-- [Or Strategy](strategy/README.md#type-orstrategy)
-- [Split Strategy](strategy/README.md#type-splitstrategy)
+- [And Strategy](strategy/README.md#AndStrategy)
+- [Majority Strategy](strategy/README.md#MajorityStrategy)
+- [MACD-RSI Strategy](strategy/compound/README.md#MacdRsiStrategy)
+- [Or Strategy](strategy/README.md#OrStrategy)
+- [Split Strategy](strategy/README.md#SplitStrategy)
### ๐ Decorator Strategies
Decorator strategies offer a way to alter the recommendations of other strategies.
-- [Inverse Strategy](strategy/decorator/README.md#type-inversestrategy)
-- [No Loss Strategy](strategy/decorator/README.md#type-nolossstrategy)
-- [Stop Loss Strategy](strategy/decorator/README.md#type-stoplossstrategy)
+- [Inverse Strategy](strategy/decorator/README.md#InverseStrategy)
+- [No Loss Strategy](strategy/decorator/README.md#NoLossStrategy)
+- [Stop Loss Strategy](strategy/decorator/README.md#StopLossStrategy)
๐ Repositories
--------------
-Repository serves as a centralized storage and retrieval location for [asset snapshots](asset/README.md#type-snapshot).
+Repository serves as a centralized storage and retrieval location for [asset snapshots](asset/README.md#Snapshot).
-The following [repository implementations](asset/README.md#type-repository) are provided.
+The following [repository implementations](asset/README.md#Repository) are provided.
-- [File System Repository](asset/README.md#type-filesystemrepository)
-- [In Memory Repository](asset/README.md#type-inmemoryrepository)
-- [Tiingo Repository](asset/README.md#type-tiingorepository)
+- [File System Repository](asset/README.md#FileSystemRepository)
+- [In Memory Repository](asset/README.md#InMemoryRepository)
+- [Tiingo Repository](asset/README.md#TiingoRepository)
- [Alpaca Markets Repository](https://github.com/cinar/indicatoralpaca)
-The [Sync function]() facilitates the synchronization of assets between designated source and target repositories by employing multi-worker concurrency for enhanced efficiency. This function serves the purpose of procuring the most recent snapshots from remote repositories and seamlessly transferring them to local repositories, such as file system repositories.
+The [Sync function](asset/README.md#Sync) facilitates the synchronization of assets between designated source and target repositories by employing multi-worker concurrency for enhanced efficiency. This function serves the purpose of procuring the most recent snapshots from remote repositories and seamlessly transferring them to local repositories, such as file system repositories.
The `indicator-sync` command line tool also offers the capability of synchronizing data between the Tiingo Repository and the File System Repository. To illustrate its usage, consider the following example command:
@@ -224,14 +225,15 @@ This command effectively retrieves the most recent snapshots for assets residing
โณ Backtesting
--------------
-The [Backtest functionality](strategy/README.md#type-backtest), using the [Outcome](strategy/README.md#func-outcome), rigorously evaluates the potential performance of the specified strategies applied to a defined set of assets. It generates comprehensive visual representations for each strategy-asset pairing.
+The [Backtest functionality](backtest/README.md#Backtest), using the [Outcome](strategy/README.md#Outcome), rigorously evaluates the potential performance of the specified strategies applied to a defined set of assets. It generates comprehensive visual representations for each strategy-asset pairing.
```go
-backtest := strategy.NewBacktest(repository, outputDir)
-backtest.Names = append(backtest.Names, "brk-b")
-backtest.Strategies = append(backtest.Strategies, trend.NewApoStrategy())
+report := backtest.NewHTMLReport(outputDir)
+bt := backtest.NewBacktest(repository, report)
+bt.Names = append(bt.Names, "brk-b")
+bt.Strategies = append(bt.Strategies, trend.NewApoStrategy())
-err = backtest.Run()
+err = bt.Run()
if err != nil {
t.Fatal(err)
}
diff --git a/strategy/momentum/README.md b/strategy/momentum/README.md
index dc89b62e..5db30354 100644
--- a/strategy/momentum/README.md
+++ b/strategy/momentum/README.md
@@ -31,6 +31,11 @@ The information provided on this project is strictly for informational purposes
- [func \(a \*AwesomeOscillatorStrategy\) Compute\(snapshots \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#AwesomeOscillatorStrategy.Compute>)
- [func \(\*AwesomeOscillatorStrategy\) Name\(\) string](<#AwesomeOscillatorStrategy.Name>)
- [func \(a \*AwesomeOscillatorStrategy\) Report\(c \<\-chan \*asset.Snapshot\) \*helper.Report](<#AwesomeOscillatorStrategy.Report>)
+- [type IchimokuCloudStrategy](<#IchimokuCloudStrategy>)
+ - [func NewIchimokuCloudStrategy\(\) \*IchimokuCloudStrategy](<#NewIchimokuCloudStrategy>)
+ - [func \(i \*IchimokuCloudStrategy\) Compute\(snapshots \<\-chan \*asset.Snapshot\) \<\-chan strategy.Action](<#IchimokuCloudStrategy.Compute>)
+ - [func \(\*IchimokuCloudStrategy\) Name\(\) string](<#IchimokuCloudStrategy.Name>)
+ - [func \(i \*IchimokuCloudStrategy\) Report\(c \<\-chan \*asset.Snapshot\) \*helper.Report](<#IchimokuCloudStrategy.Report>)
- [type RsiStrategy](<#RsiStrategy>)
- [func NewRsiStrategy\(\) \*RsiStrategy](<#NewRsiStrategy>)
- [func NewRsiStrategyWith\(buyAt, sellAt float64\) \*RsiStrategy](<#NewRsiStrategyWith>)
@@ -159,6 +164,54 @@ func (a *AwesomeOscillatorStrategy) Report(c <-chan *asset.Snapshot) *helper.Rep
Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
+
+## type [IchimokuCloudStrategy]()
+
+IchimokuCloudStrategy represents the configuration parameters for calculating the Ichimoku Cloud strategy.
+
+```go
+type IchimokuCloudStrategy struct {
+ // IchimokuCloud represents the configuration parameters for calculating the Ichimoku Cloud.
+ IchimokuCloud *momentum.IchimokuCloud[float64]
+}
+```
+
+
+### func [NewIchimokuCloudStrategy]()
+
+```go
+func NewIchimokuCloudStrategy() *IchimokuCloudStrategy
+```
+
+NewIchimokuCloudStrategy function initializes a new Ichimoku Cloud strategy with the default parameters.
+
+
+### func \(\*IchimokuCloudStrategy\) [Compute]()
+
+```go
+func (i *IchimokuCloudStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action
+```
+
+Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
+
+
+### func \(\*IchimokuCloudStrategy\) [Name]()
+
+```go
+func (*IchimokuCloudStrategy) Name() string
+```
+
+Name returns the name of the strategy.
+
+
+### func \(\*IchimokuCloudStrategy\) [Report]()
+
+```go
+func (i *IchimokuCloudStrategy) Report(c <-chan *asset.Snapshot) *helper.Report
+```
+
+Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
+
## type [RsiStrategy]()
diff --git a/strategy/momentum/ichimoku_cloud_strategy.go b/strategy/momentum/ichimoku_cloud_strategy.go
new file mode 100644
index 00000000..152d0ed7
--- /dev/null
+++ b/strategy/momentum/ichimoku_cloud_strategy.go
@@ -0,0 +1,107 @@
+// Copyright (c) 2021-2026 Onur Cinar.
+// The source code is provided under GNU AGPLv3 License.
+// https://github.com/cinar/indicator
+
+package momentum
+
+import (
+ "github.com/cinar/indicator/v2/asset"
+ "github.com/cinar/indicator/v2/helper"
+ "github.com/cinar/indicator/v2/momentum"
+ "github.com/cinar/indicator/v2/strategy"
+)
+
+// IchimokuCloudStrategy represents the configuration parameters for calculating the Ichimoku Cloud strategy.
+type IchimokuCloudStrategy struct {
+ // IchimokuCloud represents the configuration parameters for calculating the Ichimoku Cloud.
+ IchimokuCloud *momentum.IchimokuCloud[float64]
+}
+
+// NewIchimokuCloudStrategy function initializes a new Ichimoku Cloud strategy with the default parameters.
+func NewIchimokuCloudStrategy() *IchimokuCloudStrategy {
+ return &IchimokuCloudStrategy{
+ IchimokuCloud: momentum.NewIchimokuCloud[float64](),
+ }
+}
+
+// Name returns the name of the strategy.
+func (*IchimokuCloudStrategy) Name() string {
+ return "Ichimoku Cloud Strategy"
+}
+
+// Compute processes the provided asset snapshots and generates a stream of actionable recommendations.
+func (i *IchimokuCloudStrategy) Compute(snapshots <-chan *asset.Snapshot) <-chan strategy.Action {
+ snapshotsSplice := helper.Duplicate(snapshots, 3)
+
+ highs := asset.SnapshotsAsHighs(snapshotsSplice[0])
+ lows := asset.SnapshotsAsLows(snapshotsSplice[1])
+ closings := asset.SnapshotsAsClosings(snapshotsSplice[2])
+
+ closingsSplice := helper.Duplicate(closings, 2)
+
+ cl, bl, lsa, lsb, ll := i.IchimokuCloud.Compute(highs, lows, closingsSplice[0])
+
+ // Lagging line is not used in the core logic, drain it to prevent blocking
+ go helper.Drain(ll)
+
+ actions := helper.Operate5(
+ helper.Skip(closingsSplice[1], i.IchimokuCloud.IdlePeriod()),
+ cl,
+ bl,
+ lsa,
+ lsb,
+ func(c, conversion, base, spanA, spanB float64) strategy.Action {
+ if c > spanA && c > spanB && conversion > base && spanA > spanB {
+ return strategy.Buy
+ }
+
+ if c < spanA && c < spanB && conversion < base && spanA < spanB {
+ return strategy.Sell
+ }
+
+ return strategy.Hold
+ },
+ )
+
+ // Shift the actions to account for the idle period
+ return helper.Shift(actions, i.IchimokuCloud.IdlePeriod(), strategy.Hold)
+}
+
+// Report processes the provided asset snapshots and generates a report annotated with the recommended actions.
+func (i *IchimokuCloudStrategy) Report(c <-chan *asset.Snapshot) *helper.Report {
+ snapshots := helper.Duplicate(c, 6)
+
+ dates := asset.SnapshotsAsDates(snapshots[0])
+ closings := asset.SnapshotsAsClosings(snapshots[2])
+ highs := asset.SnapshotsAsHighs(snapshots[3])
+ lows := asset.SnapshotsAsLows(snapshots[4])
+ closingsForCloud := asset.SnapshotsAsClosings(snapshots[5])
+
+ cl, bl, lsa, lsb, ll := i.IchimokuCloud.Compute(highs, lows, closingsForCloud)
+
+ // Lagging line is not used in the report right now, drain it.
+ go helper.Drain(ll)
+
+ clShifted := helper.Shift(cl, i.IchimokuCloud.IdlePeriod(), 0)
+ blShifted := helper.Shift(bl, i.IchimokuCloud.IdlePeriod(), 0)
+ lsaShifted := helper.Shift(lsa, i.IchimokuCloud.IdlePeriod(), 0)
+ lsbShifted := helper.Shift(lsb, i.IchimokuCloud.IdlePeriod(), 0)
+
+ actions, outcomes := strategy.ComputeWithOutcome(i, snapshots[1])
+ annotations := strategy.ActionsToAnnotations(actions)
+ outcomes = helper.MultiplyBy(outcomes, 100)
+
+ report := helper.NewReport(i.Name(), dates)
+ report.AddChart()
+
+ report.AddColumn(helper.NewNumericReportColumn("Close", closings))
+ report.AddColumn(helper.NewNumericReportColumn("Conversion Line", clShifted))
+ report.AddColumn(helper.NewNumericReportColumn("Base Line", blShifted))
+ report.AddColumn(helper.NewNumericReportColumn("Leading Span A", lsaShifted))
+ report.AddColumn(helper.NewNumericReportColumn("Leading Span B", lsbShifted))
+ report.AddColumn(helper.NewAnnotationReportColumn(annotations), 0, 1)
+
+ report.AddColumn(helper.NewNumericReportColumn("Outcome", outcomes), 1)
+
+ return report
+}
diff --git a/strategy/momentum/ichimoku_cloud_strategy_test.go b/strategy/momentum/ichimoku_cloud_strategy_test.go
new file mode 100644
index 00000000..e00cdb2d
--- /dev/null
+++ b/strategy/momentum/ichimoku_cloud_strategy_test.go
@@ -0,0 +1,55 @@
+// Copyright (c) 2021-2026 Onur Cinar.
+// The source code is provided under GNU AGPLv3 License.
+// https://github.com/cinar/indicator
+
+package momentum_test
+
+import (
+ "testing"
+
+ "github.com/cinar/indicator/v2/asset"
+ "github.com/cinar/indicator/v2/helper"
+ "github.com/cinar/indicator/v2/strategy"
+ "github.com/cinar/indicator/v2/strategy/momentum"
+)
+
+func TestIchimokuCloudStrategy(t *testing.T) {
+ snapshots, err := helper.ReadFromCsvFile[asset.Snapshot]("testdata/brk-b.csv")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ results, err := helper.ReadFromCsvFile[strategy.Result]("testdata/ichimoku_cloud_strategy.csv")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expected := helper.Map(results, func(r *strategy.Result) strategy.Action { return r.Action })
+
+ ic := momentum.NewIchimokuCloudStrategy()
+ actual := ic.Compute(snapshots)
+
+ err = helper.CheckEquals(actual, expected)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestIchimokuCloudStrategyReport(t *testing.T) {
+ snapshots, err := helper.ReadFromCsvFile[asset.Snapshot]("testdata/brk-b.csv")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ic := momentum.NewIchimokuCloudStrategy()
+
+ report := ic.Report(snapshots)
+
+ fileName := "ichimoku_cloud_strategy.html"
+ defer helper.Remove(t, fileName)
+
+ err = report.WriteToFile(fileName)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
\ No newline at end of file
diff --git a/strategy/momentum/momentum.go b/strategy/momentum/momentum.go
index c53a559d..8a17e7bf 100644
--- a/strategy/momentum/momentum.go
+++ b/strategy/momentum/momentum.go
@@ -24,6 +24,7 @@ import "github.com/cinar/indicator/v2/strategy"
func AllStrategies() []strategy.Strategy {
return []strategy.Strategy{
NewAwesomeOscillatorStrategy(),
+ NewIchimokuCloudStrategy(),
NewRsiStrategy(),
NewStochasticRsiStrategy(),
NewTripleRsiStrategy(),
diff --git a/strategy/momentum/testdata/ichimoku_cloud_strategy.csv b/strategy/momentum/testdata/ichimoku_cloud_strategy.csv
new file mode 100644
index 00000000..45ab317c
--- /dev/null
+++ b/strategy/momentum/testdata/ichimoku_cloud_strategy.csv
@@ -0,0 +1,252 @@
+Action
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+0
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+0
+0
+0
+0
+0
+0
+1
+1
+0
+0
+0
+1
+0
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+1
+1
+1
diff --git a/trend/GEMINI.md b/trend/GEMINI.md
index a7e28156..20c41ec1 100644
--- a/trend/GEMINI.md
+++ b/trend/GEMINI.md
@@ -6,7 +6,7 @@ The `trend` package provides a collection of indicators used for identifying and
- **Moving Averages:** `Sma` (Simple), `Ema` (Exponential), `Dema` (Double), `Tema` (Triple), `Wma` (Weighted), `Hma` (Hull), `Kama` (Kaufman), `Smma` (Smoothed), `Vwma` (Volume Weighted).
- **Oscillators:** `Apo` (Absolute Price Oscillator), `Cci` (Commodity Channel Index), `Dpo` (Detrended Price Oscillator), `Trix` (Triple Exponential Average).
-- **Indicators:** `Aroon` (Aroon Oscillator), `Bop` (Balance of Power), `Macd` (Moving Average Convergence Divergence), `Roc` (Rate of Change), `Tsi` (True Strength Index).
+- **Indicators:** `Aroon` (Aroon Oscillator), `Bop` (Balance of Power), `Macd` (Moving Average Convergence Divergence), `PivotPoint` (Standard, Woodie, Camarilla, Fibonacci), `Roc` (Rate of Change), `Tsi` (True Strength Index).
- **Utilities:** `MovingMax`, `MovingMin`, `MovingSum`, `TypicalPrice`.
## Common Pattern
diff --git a/trend/README.md b/trend/README.md
index 0bdd49e9..c8bb0ae4 100644
--- a/trend/README.md
+++ b/trend/README.md
@@ -127,6 +127,14 @@ The information provided on this project is strictly for informational purposes
- [func NewMovingSumWithPeriod\[T helper.Number\]\(period int\) \*MovingSum\[T\]](<#NewMovingSumWithPeriod>)
- [func \(m \*MovingSum\[T\]\) Compute\(c \<\-chan T\) \<\-chan T](<#MovingSum[T].Compute>)
- [func \(m \*MovingSum\[T\]\) IdlePeriod\(\) int](<#MovingSum[T].IdlePeriod>)
+- [type PivotPoint](<#PivotPoint>)
+ - [func NewPivotPoint\[T helper.Float\]\(\) \*PivotPoint\[T\]](<#NewPivotPoint>)
+ - [func NewPivotPointWithMethod\[T helper.Float\]\(method PivotPointMethod\) \*PivotPoint\[T\]](<#NewPivotPointWithMethod>)
+ - [func \(p \*PivotPoint\[T\]\) Compute\(opens, highs, lows, closings \<\-chan T\) \<\-chan PivotPointResult\[T\]](<#PivotPoint[T].Compute>)
+ - [func \(p \*PivotPoint\[T\]\) IdlePeriod\(\) int](<#PivotPoint[T].IdlePeriod>)
+ - [func \(p \*PivotPoint\[T\]\) String\(\) string](<#PivotPoint[T].String>)
+- [type PivotPointMethod](<#PivotPointMethod>)
+- [type PivotPointResult](<#PivotPointResult>)
- [type Rma](<#Rma>)
- [func NewRma\[T helper.Number\]\(\) \*Rma\[T\]](<#NewRma>)
- [func NewRmaWithPeriod\[T helper.Number\]\(period int\) \*Rma\[T\]](<#NewRmaWithPeriod>)
@@ -1790,6 +1798,109 @@ func (m *MovingSum[T]) IdlePeriod() int
IdlePeriod is the initial period that Moving Sum won't yield any results.
+
+## type [PivotPoint]()
+
+PivotPoint represents the configuration parameters for calculating Pivot Points. Pivot points are calculated based on the previous period's high, low, and close, and are used to predict support and resistance levels for the current period.
+
+```go
+type PivotPoint[T helper.Float] struct {
+ // Method is the pivot point calculation method.
+ Method PivotPointMethod
+}
+```
+
+
+### func [NewPivotPoint]()
+
+```go
+func NewPivotPoint[T helper.Float]() *PivotPoint[T]
+```
+
+NewPivotPoint function initializes a new Pivot Point instance with the standard method.
+
+
+### func [NewPivotPointWithMethod]()
+
+```go
+func NewPivotPointWithMethod[T helper.Float](method PivotPointMethod) *PivotPoint[T]
+```
+
+NewPivotPointWithMethod function initializes a new Pivot Point instance with the given method.
+
+
+### func \(\*PivotPoint\[T\]\) [Compute]()
+
+```go
+func (p *PivotPoint[T]) Compute(opens, highs, lows, closings <-chan T) <-chan PivotPointResult[T]
+```
+
+Compute function takes channels for open, high, low, and closing prices and returns a channel of PivotPointResult. It uses the values from the previous period to calculate levels for the current period.
+
+
+### func \(\*PivotPoint\[T\]\) [IdlePeriod]()
+
+```go
+func (p *PivotPoint[T]) IdlePeriod() int
+```
+
+IdlePeriod is the initial period that Pivot Point won't yield any results.
+
+
+### func \(\*PivotPoint\[T\]\) [String]()
+
+```go
+func (p *PivotPoint[T]) String() string
+```
+
+String is the string representation of the Pivot Point instance.
+
+
+## type [PivotPointMethod]()
+
+PivotPointMethod represents the method used for calculating pivot points.
+
+```go
+type PivotPointMethod int
+```
+
+
+
+```go
+const (
+ // PivotPointStandard is the standard pivot point calculation.
+ PivotPointStandard PivotPointMethod = iota
+
+ // PivotPointWoodie is the Woodie pivot point calculation.
+ PivotPointWoodie
+
+ // PivotPointCamarilla is the Camarilla pivot point calculation.
+ PivotPointCamarilla
+
+ // PivotPointFibonacci is the Fibonacci pivot point calculation.
+ PivotPointFibonacci
+)
+```
+
+
+## type [PivotPointResult]()
+
+PivotPointResult represents the result of the pivot point calculation, including the pivot point itself, and its associated resistance \(R\) and support \(S\) levels.
+
+```go
+type PivotPointResult[T helper.Float] struct {
+ P T
+ R1 T
+ R2 T
+ R3 T
+ R4 T
+ S1 T
+ S2 T
+ S3 T
+ S4 T
+}
+```
+
## type [Rma]()
diff --git a/trend/pivot_point.go b/trend/pivot_point.go
new file mode 100644
index 00000000..9bd3b1ed
--- /dev/null
+++ b/trend/pivot_point.go
@@ -0,0 +1,168 @@
+// Copyright (c) 2021-2026 Onur Cinar.
+// The source code is provided under GNU AGPLv3 License.
+// https://github.com/cinar/indicator
+
+package trend
+
+import (
+ "fmt"
+
+ "github.com/cinar/indicator/v2/helper"
+)
+
+// PivotPointMethod represents the method used for calculating pivot points.
+type PivotPointMethod int
+
+const (
+ // PivotPointStandard is the standard pivot point calculation.
+ PivotPointStandard PivotPointMethod = iota
+
+ // PivotPointWoodie is the Woodie pivot point calculation.
+ PivotPointWoodie
+
+ // PivotPointCamarilla is the Camarilla pivot point calculation.
+ PivotPointCamarilla
+
+ // PivotPointFibonacci is the Fibonacci pivot point calculation.
+ PivotPointFibonacci
+)
+
+// PivotPointResult represents the result of the pivot point calculation, including
+// the pivot point itself, and its associated resistance (R) and support (S) levels.
+type PivotPointResult[T helper.Float] struct {
+ P T
+ R1 T
+ R2 T
+ R3 T
+ R4 T
+ S1 T
+ S2 T
+ S3 T
+ S4 T
+}
+
+// PivotPoint represents the configuration parameters for calculating Pivot Points.
+// Pivot points are calculated based on the previous period's high, low, and close,
+// and are used to predict support and resistance levels for the current period.
+type PivotPoint[T helper.Float] struct {
+ // Method is the pivot point calculation method.
+ Method PivotPointMethod
+}
+
+// NewPivotPoint function initializes a new Pivot Point instance with the standard method.
+func NewPivotPoint[T helper.Float]() *PivotPoint[T] {
+ return NewPivotPointWithMethod[T](PivotPointStandard)
+}
+
+// NewPivotPointWithMethod function initializes a new Pivot Point instance with the given method.
+func NewPivotPointWithMethod[T helper.Float](method PivotPointMethod) *PivotPoint[T] {
+ return &PivotPoint[T]{
+ Method: method,
+ }
+}
+
+// Compute function takes channels for open, high, low, and closing prices and
+// returns a channel of PivotPointResult. It uses the values from the previous
+// period to calculate levels for the current period.
+func (p *PivotPoint[T]) Compute(opens, highs, lows, closings <-chan T) <-chan PivotPointResult[T] {
+ result := make(chan PivotPointResult[T], cap(closings))
+
+ go func() {
+ defer close(result)
+
+ var prevH, prevL, prevC T
+ first := true
+
+ for {
+ o, okO := <-opens
+ h, okH := <-highs
+ l, okL := <-lows
+ c, okC := <-closings
+
+ if !okO || !okH || !okL || !okC {
+ break
+ }
+
+ if !first {
+ result <- p.calculate(prevH, prevL, prevC, o)
+ }
+
+ prevH, prevL, prevC = h, l, c
+ first = false
+ }
+ }()
+
+ return result
+}
+
+// calculate calculates the pivot points using the specified method.
+func (p *PivotPoint[T]) calculate(h, l, c, currO T) PivotPointResult[T] {
+ var res PivotPointResult[T]
+
+ switch p.Method {
+ case PivotPointStandard:
+ res.P = (h + l + c) / 3
+ res.R1 = 2*res.P - l
+ res.S1 = 2*res.P - h
+ res.R2 = res.P + (h - l)
+ res.S2 = res.P - (h - l)
+ res.R3 = h + 2*(res.P-l)
+ res.S3 = l - 2*(h-res.P)
+ res.R4 = h + 3*(res.P-l)
+ res.S4 = l - 3*(h-res.P)
+
+ case PivotPointWoodie:
+ res.P = (h + l + 2*currO) / 4
+ res.R1 = 2*res.P - l
+ res.S1 = 2*res.P - h
+ res.R2 = res.P + (h - l)
+ res.S2 = res.P - (h - l)
+ res.R3 = h + 2*(res.P-l)
+ res.S3 = l - 2*(h-res.P)
+
+ case PivotPointCamarilla:
+ diff := h - l
+ res.P = (h + l + c) / 3
+ res.R1 = c + diff*T(1.1)/12
+ res.R2 = c + diff*T(1.1)/6
+ res.R3 = c + diff*T(1.1)/4
+ res.R4 = c + diff*T(1.1)/2
+ res.S1 = c - diff*T(1.1)/12
+ res.S2 = c - diff*T(1.1)/6
+ res.S3 = c - diff*T(1.1)/4
+ res.S4 = c - diff*T(1.1)/2
+
+ case PivotPointFibonacci:
+ diff := h - l
+ res.P = (h + l + c) / 3
+ res.R1 = res.P + diff*T(0.382)
+ res.S1 = res.P - diff*T(0.382)
+ res.R2 = res.P + diff*T(0.618)
+ res.S2 = res.P - diff*T(0.618)
+ res.R3 = res.P + diff*T(1.000)
+ res.S3 = res.P - diff*T(1.000)
+ }
+
+ return res
+}
+
+// IdlePeriod is the initial period that Pivot Point won't yield any results.
+func (p *PivotPoint[T]) IdlePeriod() int {
+ return 1
+}
+
+// String is the string representation of the Pivot Point instance.
+func (p *PivotPoint[T]) String() string {
+ var methodStr string
+ switch p.Method {
+ case PivotPointStandard:
+ methodStr = "Standard"
+ case PivotPointWoodie:
+ methodStr = "Woodie"
+ case PivotPointCamarilla:
+ methodStr = "Camarilla"
+ case PivotPointFibonacci:
+ methodStr = "Fibonacci"
+ }
+ return fmt.Sprintf("PivotPoint(%s)", methodStr)
+}
diff --git a/trend/pivot_point_test.go b/trend/pivot_point_test.go
new file mode 100644
index 00000000..0733c36b
--- /dev/null
+++ b/trend/pivot_point_test.go
@@ -0,0 +1,118 @@
+// Copyright (c) 2021-2026 Onur Cinar.
+// The source code is provided under GNU AGPLv3 License.
+// https://github.com/cinar/indicator
+
+package trend_test
+
+import (
+ "testing"
+
+ "github.com/cinar/indicator/v2/helper"
+ "github.com/cinar/indicator/v2/trend"
+)
+
+func TestPivotPoint(t *testing.T) {
+ type Data struct {
+ Open float64 `header:"Open"`
+ High float64 `header:"High"`
+ Low float64 `header:"Low"`
+ Close float64 `header:"Close"`
+ }
+
+ input, err := helper.ReadFromCsvFile[Data]("../helper/testdata/report.csv")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ inputs := helper.Duplicate(input, 4)
+ opens := helper.Map(inputs[0], func(d *Data) float64 { return d.Open })
+ highs := helper.Map(inputs[1], func(d *Data) float64 { return d.High })
+ lows := helper.Map(inputs[2], func(d *Data) float64 { return d.Low })
+ closings := helper.Map(inputs[3], func(d *Data) float64 { return d.Close })
+
+ pp := trend.NewPivotPoint[float64]()
+ results := pp.Compute(opens, highs, lows, closings)
+
+ // First bar: 315.130005, 318.600006, 308.700012, 318.600006
+ // Second bar Open: 319
+ // Standard Pivot Point for second bar:
+ // P = (318.600006 + 308.700012 + 318.600006) / 3 = 315.300008
+ // R1 = 2 * 315.300008 - 308.700012 = 321.900004
+ // S1 = 2 * 315.300008 - 318.600006 = 312.00001
+
+ res := <-results
+
+ if helper.RoundDigit(res.P, 6) != 315.300008 {
+ t.Fatalf("expected P 315.300008, got %v", res.P)
+ }
+
+ if helper.RoundDigit(res.R1, 6) != 321.900004 {
+ t.Fatalf("expected R1 321.900004, got %v", res.R1)
+ }
+
+ if helper.RoundDigit(res.S1, 6) != 312.00001 {
+ t.Fatalf("expected S1 312.00001, got %v", res.S1)
+ }
+}
+
+func TestPivotPointWoodie(t *testing.T) {
+ type Data struct {
+ Open float64 `header:"Open"`
+ High float64 `header:"High"`
+ Low float64 `header:"Low"`
+ Close float64 `header:"Close"`
+ }
+
+ input, err := helper.ReadFromCsvFile[Data]("../helper/testdata/report.csv")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ inputs := helper.Duplicate(input, 4)
+ opens := helper.Map(inputs[0], func(d *Data) float64 { return d.Open })
+ highs := helper.Map(inputs[1], func(d *Data) float64 { return d.High })
+ lows := helper.Map(inputs[2], func(d *Data) float64 { return d.Low })
+ closings := helper.Map(inputs[3], func(d *Data) float64 { return d.Close })
+
+ pp := trend.NewPivotPointWithMethod[float64](trend.PivotPointWoodie)
+ results := pp.Compute(opens, highs, lows, closings)
+
+ // First bar: H=318.600006, L=308.700012
+ // Second bar: O=319
+ // Woodie P = (318.600006 + 308.700012 + 2 * 319) / 4 = 316.3250045
+
+ res := <-results
+
+ if helper.RoundDigit(res.P, 7) != 316.3250045 {
+ t.Fatalf("expected P 316.3250045, got %v", res.P)
+ }
+}
+
+func TestPivotPointIdlePeriod(t *testing.T) {
+ pp := trend.NewPivotPoint[float64]()
+ if pp.IdlePeriod() != 1 {
+ t.Fatalf("expected IdlePeriod 1, got %d", pp.IdlePeriod())
+ }
+}
+
+func TestPivotPointString(t *testing.T) {
+ pp := trend.NewPivotPoint[float64]()
+ if pp.String() != "PivotPoint(Standard)" {
+ t.Fatalf("expected PivotPoint(Standard), got %s", pp.String())
+ }
+
+ pp = trend.NewPivotPointWithMethod[float64](trend.PivotPointWoodie)
+ if pp.String() != "PivotPoint(Woodie)" {
+ t.Fatalf("expected PivotPoint(Woodie), got %s", pp.String())
+ }
+
+ pp = trend.NewPivotPointWithMethod[float64](trend.PivotPointCamarilla)
+ if pp.String() != "PivotPoint(Camarilla)" {
+ t.Fatalf("expected PivotPoint(Camarilla), got %s", pp.String())
+ }
+
+ pp = trend.NewPivotPointWithMethod[float64](trend.PivotPointFibonacci)
+ if pp.String() != "PivotPoint(Fibonacci)" {
+ t.Fatalf("expected PivotPoint(Fibonacci), got %s", pp.String())
+ }
+}