90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
package strategy
|
||
|
||
import (
|
||
"sync/atomic"
|
||
|
||
"github.com/shopspring/decimal"
|
||
)
|
||
|
||
// =========================
|
||
// MACD(單寫;快照多讀)
|
||
// fastEMA / slowEMA 吃「收盤價」;signalEMA 吃「MACDLine」
|
||
// 與 EMA/SMA 一致風格:Update()(單寫)、Load()(多讀)
|
||
// =========================
|
||
|
||
// MACDSnapshot 對外發佈的不可變快照
|
||
type MACDSnapshot struct {
|
||
Params [3]uint // (fast, slow, signal)
|
||
LastPrice decimal.Decimal // 最近一次喂入的收盤價
|
||
MACDLine decimal.Decimal // DIF = fastEMA - slowEMA
|
||
SignalLine decimal.Decimal // DEA = EMA(MACDLine, signalPeriod)
|
||
Histogram decimal.Decimal // Hist = MACDLine - SignalLine
|
||
Ready bool // 三條線皆 ready 才會 true
|
||
}
|
||
|
||
// MACD 快照發佈器(單寫多讀)
|
||
type MACD struct {
|
||
// 內部用你已完成的 EMA(其本身就含 SMA-seed 與 ready 狀態)
|
||
fastEMA *EMA
|
||
slowEMA *EMA
|
||
signalEMA *EMA
|
||
|
||
fastPeriod, slowPeriod, signalPeriod uint
|
||
|
||
last decimal.Decimal // 只作紀錄(debug/觀察用)
|
||
snap atomic.Value // holds MACDSnapshot
|
||
}
|
||
|
||
// NewMACD 建立 MACD(預設 12,26,9;也可自訂)
|
||
func NewMACD(fast, slow, signal uint) *MACD {
|
||
if !(fast > 0 && slow > 0 && signal > 0) {
|
||
panic("MACD periods must be > 0")
|
||
}
|
||
if fast >= slow {
|
||
panic("MACD requires fast < slow (e.g., 12 < 26)")
|
||
}
|
||
|
||
m := &MACD{
|
||
fastEMA: NewEMA(fast),
|
||
slowEMA: NewEMA(slow),
|
||
signalEMA: NewEMA(signal),
|
||
fastPeriod: fast,
|
||
slowPeriod: slow,
|
||
signalPeriod: signal,
|
||
}
|
||
// 初始化一個空快照
|
||
m.snap.Store(MACDSnapshot{Params: [3]uint{fast, slow, signal}})
|
||
return m
|
||
}
|
||
|
||
// Update 僅供單一 writer 呼叫;回傳並發佈最新快照
|
||
func (m *MACD) Update(close decimal.Decimal) MACDSnapshot {
|
||
// 先用 EMA(你已改好的版本)各自更新快、慢線
|
||
fast := m.fastEMA.Update(close)
|
||
slow := m.slowEMA.Update(close)
|
||
|
||
macdLine := fast.Value.Sub(slow.Value)
|
||
|
||
// 信號線吃的是 MACDLine(非收盤價)
|
||
sig := m.signalEMA.Update(macdLine)
|
||
|
||
ready := fast.Ready && slow.Ready && sig.Ready
|
||
|
||
snap := MACDSnapshot{
|
||
Params: [3]uint{m.fastPeriod, m.slowPeriod, m.signalPeriod},
|
||
LastPrice: close,
|
||
MACDLine: macdLine,
|
||
SignalLine: sig.Value,
|
||
Histogram: macdLine.Sub(sig.Value),
|
||
Ready: ready,
|
||
}
|
||
m.last = close
|
||
m.snap.Store(snap)
|
||
return snap
|
||
}
|
||
|
||
// Load 多 goroutine 零鎖讀取最新快照
|
||
func (m *MACD) Load() MACDSnapshot {
|
||
return m.snap.Load().(MACDSnapshot)
|
||
}
|