more iterating on macd, need to get a better handle on how to test.
This commit is contained in:
parent
7858457772
commit
32dd907bf8
9 changed files with 464 additions and 246 deletions
287
macd_series.go
287
macd_series.go
|
|
@ -1,37 +1,45 @@
|
|||
package chart
|
||||
|
||||
const (
|
||||
// DefaultMACDWindowPrimary is the long window.
|
||||
DefaultMACDWindowPrimary = 26
|
||||
// DefaultMACDWindowSecondary is the short window.
|
||||
DefaultMACDWindowSecondary = 12
|
||||
// DefaultMACDPeriodPrimary is the long window.
|
||||
DefaultMACDPeriodPrimary = 26
|
||||
// DefaultMACDPeriodSecondary is the short window.
|
||||
DefaultMACDPeriodSecondary = 12
|
||||
// DefaultMACDSignalPeriod is the signal period to compute for the MACD.
|
||||
DefaultMACDSignalPeriod = 9
|
||||
)
|
||||
|
||||
// MACDSeries (or Moving Average Convergence Divergence) is a special type of series that
|
||||
// computes the difference between two different EMA values for a given index, as denoted by WindowPrimary(26) and WindowSecondary(12).
|
||||
// MACDSeries computes the difference between the MACD line and the MACD Signal line.
|
||||
// It is used in technical analysis and gives a lagging indicator of momentum.
|
||||
type MACDSeries struct {
|
||||
Name string
|
||||
Style Style
|
||||
YAxis YAxisType
|
||||
InnerSeries ValueProvider
|
||||
|
||||
WindowPrimary int
|
||||
WindowSecondary int
|
||||
PrimaryPeriod int
|
||||
SecondaryPeriod int
|
||||
SignalPeriod int
|
||||
|
||||
Sigma float64
|
||||
}
|
||||
|
||||
// GetWindows returns the primary and secondary window sizes.
|
||||
func (macd MACDSeries) GetWindows() (w1, w2 int) {
|
||||
if macd.WindowPrimary == 0 {
|
||||
w1 = DefaultMACDWindowPrimary
|
||||
// GetPeriods returns the primary and secondary periods.
|
||||
func (macd MACDSeries) GetPeriods() (w1, w2, sig int) {
|
||||
if macd.PrimaryPeriod == 0 {
|
||||
w1 = DefaultMACDPeriodPrimary
|
||||
} else {
|
||||
w1 = macd.WindowPrimary
|
||||
w1 = macd.PrimaryPeriod
|
||||
}
|
||||
if macd.WindowSecondary == 0 {
|
||||
w2 = DefaultMACDWindowSecondary
|
||||
if macd.SecondaryPeriod == 0 {
|
||||
w2 = DefaultMACDPeriodSecondary
|
||||
} else {
|
||||
w2 = macd.WindowSecondary
|
||||
w2 = macd.SecondaryPeriod
|
||||
}
|
||||
if macd.SignalPeriod == 0 {
|
||||
sig = DefaultMACDSignalPeriod
|
||||
} else {
|
||||
sig = macd.SignalPeriod
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -42,7 +50,7 @@ func (macd MACDSeries) GetSigma(defaults ...float64) float64 {
|
|||
if len(defaults) > 0 {
|
||||
return defaults[0]
|
||||
}
|
||||
return DefaultExponentialMovingAverageSigma
|
||||
return DefaultEMASigma
|
||||
}
|
||||
return macd.Sigma
|
||||
}
|
||||
|
|
@ -68,7 +76,7 @@ func (macd MACDSeries) Len() int {
|
|||
return 0
|
||||
}
|
||||
|
||||
w1, _ := macd.GetWindows()
|
||||
w1, _, _ := macd.GetPeriods()
|
||||
innerLen := macd.InnerSeries.Len()
|
||||
if innerLen > w1 {
|
||||
return innerLen - w1
|
||||
|
|
@ -76,35 +84,250 @@ func (macd MACDSeries) Len() int {
|
|||
return 0
|
||||
}
|
||||
|
||||
// GetValue gets a value at a given index.
|
||||
// GetValue gets a value at a given index. For MACD it is the signal value.
|
||||
func (macd MACDSeries) GetValue(index int) (x float64, y float64) {
|
||||
if macd.InnerSeries == nil {
|
||||
return
|
||||
}
|
||||
|
||||
w1, w2 := macd.GetWindows()
|
||||
w1, w2, sig := macd.GetPeriods()
|
||||
sigma := macd.GetSigma()
|
||||
|
||||
effectiveIndex := index + w1
|
||||
x, _ = macd.InnerSeries.GetValue(effectiveIndex)
|
||||
|
||||
ema1 := macd.computeEMA(w1, effectiveIndex)
|
||||
ema2 := macd.computeEMA(w2, effectiveIndex)
|
||||
signal := EMASeries{
|
||||
InnerSeries: MACDLineSeries{
|
||||
InnerSeries: macd.InnerSeries,
|
||||
PrimaryPeriod: w1,
|
||||
SecondaryPeriod: w2,
|
||||
Sigma: sigma,
|
||||
},
|
||||
Sigma: sigma,
|
||||
Period: sig,
|
||||
}
|
||||
|
||||
macdl := MACDLineSeries{
|
||||
InnerSeries: macd.InnerSeries,
|
||||
PrimaryPeriod: w1,
|
||||
SecondaryPeriod: w2,
|
||||
Sigma: sigma,
|
||||
}
|
||||
|
||||
_, sv := signal.GetValue(index)
|
||||
_, lv := macdl.GetValue(index)
|
||||
y = lv - sv
|
||||
|
||||
y = ema1 - ema2
|
||||
return
|
||||
}
|
||||
|
||||
func (macd MACDSeries) computeEMA(windowSize int, index int) float64 {
|
||||
_, v := macd.InnerSeries.GetValue(index)
|
||||
if windowSize == 1 {
|
||||
return v
|
||||
// MACDSignalSeries computes the EMA of the MACDLineSeries.
|
||||
type MACDSignalSeries struct {
|
||||
Name string
|
||||
Style Style
|
||||
YAxis YAxisType
|
||||
InnerSeries ValueProvider
|
||||
|
||||
PrimaryPeriod int
|
||||
SecondaryPeriod int
|
||||
SignalPeriod int
|
||||
|
||||
Sigma float64
|
||||
}
|
||||
|
||||
// GetPeriods returns the primary and secondary periods.
|
||||
func (macds MACDSignalSeries) GetPeriods() (w1, w2, sig int) {
|
||||
if macds.PrimaryPeriod == 0 {
|
||||
w1 = DefaultMACDPeriodPrimary
|
||||
} else {
|
||||
w1 = macds.PrimaryPeriod
|
||||
}
|
||||
sig := macd.GetSigma()
|
||||
return sig*v + ((1.0 - sig) * macd.computeEMA(windowSize-1, index-1))
|
||||
if macds.SecondaryPeriod == 0 {
|
||||
w2 = DefaultMACDPeriodSecondary
|
||||
} else {
|
||||
w2 = macds.SecondaryPeriod
|
||||
}
|
||||
if macds.SignalPeriod == 0 {
|
||||
sig = DefaultMACDSignalPeriod
|
||||
} else {
|
||||
sig = macds.SignalPeriod
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetSigma returns the smoothing factor for the serise.
|
||||
func (macds MACDSignalSeries) GetSigma(defaults ...float64) float64 {
|
||||
if macds.Sigma == 0 {
|
||||
if len(defaults) > 0 {
|
||||
return defaults[0]
|
||||
}
|
||||
return DefaultEMASigma
|
||||
}
|
||||
return macds.Sigma
|
||||
}
|
||||
|
||||
// GetName returns the name of the time series.
|
||||
func (macds MACDSignalSeries) GetName() string {
|
||||
return macds.Name
|
||||
}
|
||||
|
||||
// GetStyle returns the line style.
|
||||
func (macds MACDSignalSeries) GetStyle() Style {
|
||||
return macds.Style
|
||||
}
|
||||
|
||||
// GetYAxis returns which YAxis the series draws on.
|
||||
func (macds MACDSignalSeries) GetYAxis() YAxisType {
|
||||
return macds.YAxis
|
||||
}
|
||||
|
||||
// Len returns the number of elements in the series.
|
||||
func (macds MACDSignalSeries) Len() int {
|
||||
if macds.InnerSeries == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
w1, _, _ := macds.GetPeriods()
|
||||
innerLen := macds.InnerSeries.Len()
|
||||
if innerLen > w1 {
|
||||
return innerLen - w1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetValue gets a value at a given index. For MACD it is the signal value.
|
||||
func (macds MACDSignalSeries) GetValue(index int) (x float64, y float64) {
|
||||
if macds.InnerSeries == nil {
|
||||
return
|
||||
}
|
||||
|
||||
w1, w2, sig := macds.GetPeriods()
|
||||
sigma := macds.GetSigma()
|
||||
|
||||
effectiveIndex := index + w1
|
||||
x, _ = macds.InnerSeries.GetValue(effectiveIndex)
|
||||
|
||||
signal := EMASeries{
|
||||
InnerSeries: MACDLineSeries{
|
||||
InnerSeries: macds.InnerSeries,
|
||||
PrimaryPeriod: w1,
|
||||
SecondaryPeriod: w2,
|
||||
Sigma: sigma,
|
||||
},
|
||||
Sigma: sigma,
|
||||
Period: sig,
|
||||
}
|
||||
|
||||
_, y = signal.GetValue(index)
|
||||
return
|
||||
}
|
||||
|
||||
// Render renders the series.
|
||||
func (macd MACDSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
||||
style := macd.Style.WithDefaultsFrom(defaults)
|
||||
DrawLineSeries(r, canvasBox, xrange, yrange, style, macd)
|
||||
func (macds MACDSignalSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
||||
style := macds.Style.WithDefaultsFrom(defaults)
|
||||
DrawLineSeries(r, canvasBox, xrange, yrange, style, macds)
|
||||
}
|
||||
|
||||
// MACDLineSeries is a series that computes the inner ema1-ema2 value as a series.
|
||||
type MACDLineSeries struct {
|
||||
Name string
|
||||
Style Style
|
||||
YAxis YAxisType
|
||||
InnerSeries ValueProvider
|
||||
|
||||
PrimaryPeriod int
|
||||
SecondaryPeriod int
|
||||
|
||||
Sigma float64
|
||||
}
|
||||
|
||||
// GetName returns the name of the time series.
|
||||
func (macdl MACDLineSeries) GetName() string {
|
||||
return macdl.Name
|
||||
}
|
||||
|
||||
// GetStyle returns the line style.
|
||||
func (macdl MACDLineSeries) GetStyle() Style {
|
||||
return macdl.Style
|
||||
}
|
||||
|
||||
// GetYAxis returns which YAxis the series draws on.
|
||||
func (macdl MACDLineSeries) GetYAxis() YAxisType {
|
||||
return macdl.YAxis
|
||||
}
|
||||
|
||||
// GetPeriods returns the primary and secondary periods.
|
||||
func (macdl MACDLineSeries) GetPeriods() (w1, w2 int) {
|
||||
if macdl.PrimaryPeriod == 0 {
|
||||
w1 = DefaultMACDPeriodPrimary
|
||||
} else {
|
||||
w1 = macdl.PrimaryPeriod
|
||||
}
|
||||
if macdl.SecondaryPeriod == 0 {
|
||||
w2 = DefaultMACDPeriodSecondary
|
||||
} else {
|
||||
w2 = macdl.SecondaryPeriod
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Len returns the number of elements in the series.
|
||||
func (macdl MACDLineSeries) Len() int {
|
||||
if macdl.InnerSeries == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
w1, _ := macdl.GetPeriods()
|
||||
innerLen := macdl.InnerSeries.Len()
|
||||
if innerLen > w1 {
|
||||
return innerLen - w1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetSigma returns the smoothing factor for the serise.
|
||||
func (macdl MACDLineSeries) GetSigma(defaults ...float64) float64 {
|
||||
if macdl.Sigma == 0 {
|
||||
if len(defaults) > 0 {
|
||||
return defaults[0]
|
||||
}
|
||||
return DefaultEMASigma
|
||||
}
|
||||
return macdl.Sigma
|
||||
}
|
||||
|
||||
// GetValue gets a value at a given index. For MACD it is the signal value.
|
||||
func (macdl MACDLineSeries) GetValue(index int) (x float64, y float64) {
|
||||
if macdl.InnerSeries == nil {
|
||||
return
|
||||
}
|
||||
|
||||
w1, w2 := macdl.GetPeriods()
|
||||
|
||||
effectiveIndex := index + w1
|
||||
x, _ = macdl.InnerSeries.GetValue(effectiveIndex)
|
||||
|
||||
ema1 := EMASeries{
|
||||
InnerSeries: macdl.InnerSeries,
|
||||
Period: w1,
|
||||
Sigma: macdl.GetSigma(),
|
||||
}
|
||||
|
||||
ema2 := EMASeries{
|
||||
InnerSeries: macdl.InnerSeries,
|
||||
Period: w2,
|
||||
Sigma: macdl.GetSigma(),
|
||||
}
|
||||
|
||||
_, emav1 := ema1.GetValue(index)
|
||||
_, emav2 := ema2.GetValue(index)
|
||||
|
||||
y = emav1 - emav2
|
||||
return
|
||||
}
|
||||
|
||||
// Render renders the series.
|
||||
func (macdl MACDLineSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
||||
style := macdl.Style.WithDefaultsFrom(defaults)
|
||||
DrawLineSeries(r, canvasBox, xrange, yrange, style, macdl)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue