blockchain/internal/lib/strategy/macd.go

90 lines
2.4 KiB
Go
Raw Permalink Normal View History

2025-08-17 14:48:13 +00:00
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)
}