fixing macd and ema performance issues.
This commit is contained in:
parent
befd626bbe
commit
8af50213c3
2 changed files with 84 additions and 48 deletions
|
@ -13,6 +13,8 @@ type EMASeries struct {
|
||||||
|
|
||||||
Period int
|
Period int
|
||||||
InnerSeries ValueProvider
|
InnerSeries ValueProvider
|
||||||
|
|
||||||
|
cache []float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the time series.
|
// GetName returns the name of the time series.
|
||||||
|
@ -49,39 +51,51 @@ func (ema EMASeries) GetSigma() float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue gets a value at a given index.
|
// GetValue gets a value at a given index.
|
||||||
func (ema EMASeries) GetValue(index int) (x, y float64) {
|
func (ema *EMASeries) GetValue(index int) (x, y float64) {
|
||||||
if ema.InnerSeries == nil {
|
if ema.InnerSeries == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(ema.cache) == 0 {
|
||||||
|
ema.ensureCachedValues()
|
||||||
|
}
|
||||||
vx, _ := ema.InnerSeries.GetValue(index)
|
vx, _ := ema.InnerSeries.GetValue(index)
|
||||||
x = vx
|
x = vx
|
||||||
y = ema.compute(ema.GetPeriod(), index)
|
y = ema.cache[index]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLastValue computes the last moving average value but walking back window size samples,
|
// GetLastValue computes the last moving average value but walking back window size samples,
|
||||||
// and recomputing the last moving average chunk.
|
// and recomputing the last moving average chunk.
|
||||||
func (ema EMASeries) GetLastValue() (x, y float64) {
|
func (ema *EMASeries) GetLastValue() (x, y float64) {
|
||||||
if ema.InnerSeries == nil {
|
if ema.InnerSeries == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(ema.cache) == 0 {
|
||||||
|
ema.ensureCachedValues()
|
||||||
|
}
|
||||||
lastIndex := ema.InnerSeries.Len() - 1
|
lastIndex := ema.InnerSeries.Len() - 1
|
||||||
x, _ = ema.InnerSeries.GetValue(lastIndex)
|
x, _ = ema.InnerSeries.GetValue(lastIndex)
|
||||||
y = ema.compute(ema.GetPeriod(), lastIndex)
|
y = ema.cache[lastIndex]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ema EMASeries) compute(period, index int) float64 {
|
func (ema *EMASeries) ensureCachedValues() {
|
||||||
_, v := ema.InnerSeries.GetValue(index)
|
seriesLength := ema.InnerSeries.Len()
|
||||||
if index == 0 {
|
ema.cache = make([]float64, seriesLength)
|
||||||
return v
|
sigma := ema.GetSigma()
|
||||||
|
for x := 0; x < seriesLength; x++ {
|
||||||
|
_, y := ema.InnerSeries.GetValue(x)
|
||||||
|
if x == 0 {
|
||||||
|
ema.cache[x] = y
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
previousEMA := ema.cache[x-1]
|
||||||
|
ema.cache[x] = ((y - previousEMA) * sigma) + previousEMA
|
||||||
}
|
}
|
||||||
previousEMA := ema.compute(period-1, index-1)
|
|
||||||
return ((v - previousEMA) * ema.GetSigma()) + previousEMA
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render renders the series.
|
// Render renders the series.
|
||||||
func (ema EMASeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
func (ema *EMASeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
||||||
style := ema.Style.WithDefaultsFrom(defaults)
|
style := ema.Style.WithDefaultsFrom(defaults)
|
||||||
DrawLineSeries(r, canvasBox, xrange, yrange, style, ema)
|
DrawLineSeries(r, canvasBox, xrange, yrange, style, ema)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,9 @@ type MACDSeries struct {
|
||||||
PrimaryPeriod int
|
PrimaryPeriod int
|
||||||
SecondaryPeriod int
|
SecondaryPeriod int
|
||||||
SignalPeriod int
|
SignalPeriod int
|
||||||
|
|
||||||
|
signal *MACDSignalSeries
|
||||||
|
macdl *MACDLineSeries
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPeriods returns the primary and secondary periods.
|
// GetPeriods returns the primary and secondary periods.
|
||||||
|
@ -67,33 +70,39 @@ func (macd MACDSeries) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue gets a value at a given index. For MACD it is the signal value.
|
// 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) {
|
func (macd *MACDSeries) GetValue(index int) (x float64, y float64) {
|
||||||
if macd.InnerSeries == nil {
|
if macd.InnerSeries == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w1, w2, sig := macd.GetPeriods()
|
if macd.signal == nil || macd.macdl == nil {
|
||||||
|
macd.ensureChildSeries()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, lv := macd.macdl.GetValue(index)
|
||||||
|
_, sv := macd.signal.GetValue(index)
|
||||||
|
|
||||||
x, _ = macd.InnerSeries.GetValue(index)
|
x, _ = macd.InnerSeries.GetValue(index)
|
||||||
|
y = lv - sv
|
||||||
|
|
||||||
signal := MACDSignalSeries{
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (macd *MACDSeries) ensureChildSeries() {
|
||||||
|
w1, w2, sig := macd.GetPeriods()
|
||||||
|
|
||||||
|
macd.signal = &MACDSignalSeries{
|
||||||
InnerSeries: macd.InnerSeries,
|
InnerSeries: macd.InnerSeries,
|
||||||
PrimaryPeriod: w1,
|
PrimaryPeriod: w1,
|
||||||
SecondaryPeriod: w2,
|
SecondaryPeriod: w2,
|
||||||
SignalPeriod: sig,
|
SignalPeriod: sig,
|
||||||
}
|
}
|
||||||
|
|
||||||
macdl := MACDLineSeries{
|
macd.macdl = &MACDLineSeries{
|
||||||
InnerSeries: macd.InnerSeries,
|
InnerSeries: macd.InnerSeries,
|
||||||
PrimaryPeriod: w1,
|
PrimaryPeriod: w1,
|
||||||
SecondaryPeriod: w2,
|
SecondaryPeriod: w2,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, lv := macdl.GetValue(index)
|
|
||||||
_, sv := signal.GetValue(index)
|
|
||||||
y = lv - sv
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MACDSignalSeries computes the EMA of the MACDLineSeries.
|
// MACDSignalSeries computes the EMA of the MACDLineSeries.
|
||||||
|
@ -106,6 +115,8 @@ type MACDSignalSeries struct {
|
||||||
PrimaryPeriod int
|
PrimaryPeriod int
|
||||||
SecondaryPeriod int
|
SecondaryPeriod int
|
||||||
SignalPeriod int
|
SignalPeriod int
|
||||||
|
|
||||||
|
signal *EMASeries
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPeriods returns the primary and secondary periods.
|
// GetPeriods returns the primary and secondary periods.
|
||||||
|
@ -144,7 +155,7 @@ func (macds MACDSignalSeries) GetYAxis() YAxisType {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the number of elements in the series.
|
// Len returns the number of elements in the series.
|
||||||
func (macds MACDSignalSeries) Len() int {
|
func (macds *MACDSignalSeries) Len() int {
|
||||||
if macds.InnerSeries == nil {
|
if macds.InnerSeries == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -153,30 +164,34 @@ func (macds MACDSignalSeries) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue gets a value at a given index. For MACD it is the signal value.
|
// 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) {
|
func (macds *MACDSignalSeries) GetValue(index int) (x float64, y float64) {
|
||||||
if macds.InnerSeries == nil {
|
if macds.InnerSeries == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if macds.signal == nil {
|
||||||
|
macds.ensureSignal()
|
||||||
|
}
|
||||||
|
x, _ = macds.InnerSeries.GetValue(index)
|
||||||
|
_, y = macds.signal.GetValue(index)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (macds *MACDSignalSeries) ensureSignal() {
|
||||||
w1, w2, sig := macds.GetPeriods()
|
w1, w2, sig := macds.GetPeriods()
|
||||||
|
|
||||||
x, _ = macds.InnerSeries.GetValue(index)
|
macds.signal = &EMASeries{
|
||||||
|
InnerSeries: &MACDLineSeries{
|
||||||
signal := EMASeries{
|
|
||||||
InnerSeries: MACDLineSeries{
|
|
||||||
InnerSeries: macds.InnerSeries,
|
InnerSeries: macds.InnerSeries,
|
||||||
PrimaryPeriod: w1,
|
PrimaryPeriod: w1,
|
||||||
SecondaryPeriod: w2,
|
SecondaryPeriod: w2,
|
||||||
},
|
},
|
||||||
Period: sig,
|
Period: sig,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, y = signal.GetValue(index)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render renders the series.
|
// Render renders the series.
|
||||||
func (macds MACDSignalSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
func (macds *MACDSignalSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
||||||
style := macds.Style.WithDefaultsFrom(defaults)
|
style := macds.Style.WithDefaultsFrom(defaults)
|
||||||
DrawLineSeries(r, canvasBox, xrange, yrange, style, macds)
|
DrawLineSeries(r, canvasBox, xrange, yrange, style, macds)
|
||||||
}
|
}
|
||||||
|
@ -191,6 +206,9 @@ type MACDLineSeries struct {
|
||||||
PrimaryPeriod int
|
PrimaryPeriod int
|
||||||
SecondaryPeriod int
|
SecondaryPeriod int
|
||||||
|
|
||||||
|
ema1 *EMASeries
|
||||||
|
ema2 *EMASeries
|
||||||
|
|
||||||
Sigma float64
|
Sigma float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +243,7 @@ func (macdl MACDLineSeries) GetPeriods() (w1, w2 int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the number of elements in the series.
|
// Len returns the number of elements in the series.
|
||||||
func (macdl MACDLineSeries) Len() int {
|
func (macdl *MACDLineSeries) Len() int {
|
||||||
if macdl.InnerSeries == nil {
|
if macdl.InnerSeries == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -234,34 +252,38 @@ func (macdl MACDLineSeries) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue gets a value at a given index. For MACD it is the signal value.
|
// 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) {
|
func (macdl *MACDLineSeries) GetValue(index int) (x float64, y float64) {
|
||||||
if macdl.InnerSeries == nil {
|
if macdl.InnerSeries == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if macdl.ema1 == nil && macdl.ema2 == nil {
|
||||||
w1, w2 := macdl.GetPeriods()
|
macdl.ensureEMASeries()
|
||||||
|
}
|
||||||
|
|
||||||
x, _ = macdl.InnerSeries.GetValue(index)
|
x, _ = macdl.InnerSeries.GetValue(index)
|
||||||
|
|
||||||
ema1 := EMASeries{
|
_, emav1 := macdl.ema1.GetValue(index)
|
||||||
InnerSeries: macdl.InnerSeries,
|
_, emav2 := macdl.ema2.GetValue(index)
|
||||||
Period: w1,
|
|
||||||
}
|
|
||||||
|
|
||||||
ema2 := EMASeries{
|
|
||||||
InnerSeries: macdl.InnerSeries,
|
|
||||||
Period: w2,
|
|
||||||
}
|
|
||||||
|
|
||||||
_, emav1 := ema1.GetValue(index)
|
|
||||||
_, emav2 := ema2.GetValue(index)
|
|
||||||
|
|
||||||
y = emav2 - emav1
|
y = emav2 - emav1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (macdl *MACDLineSeries) ensureEMASeries() {
|
||||||
|
w1, w2 := macdl.GetPeriods()
|
||||||
|
|
||||||
|
macdl.ema1 = &EMASeries{
|
||||||
|
InnerSeries: macdl.InnerSeries,
|
||||||
|
Period: w1,
|
||||||
|
}
|
||||||
|
macdl.ema2 = &EMASeries{
|
||||||
|
InnerSeries: macdl.InnerSeries,
|
||||||
|
Period: w2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Render renders the series.
|
// Render renders the series.
|
||||||
func (macdl MACDLineSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
func (macdl *MACDLineSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
|
||||||
style := macdl.Style.WithDefaultsFrom(defaults)
|
style := macdl.Style.WithDefaultsFrom(defaults)
|
||||||
DrawLineSeries(r, canvasBox, xrange, yrange, style, macdl)
|
DrawLineSeries(r, canvasBox, xrange, yrange, style, macdl)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue