You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

105 lines
2.5 KiB

package strategy
import (
"sig-pub/pkg/types"
)
// MeanReversionV1
type MeanReversionV1 struct {
IIntervalSigStrategy
interval types.Interval
period int
threshold float64
buckets int
}
func (s *MeanReversionV1) New() ISigStrategy {
return &MeanReversionV1{}
}
func (s *MeanReversionV1) Meta() StrategyMeta {
return StrategyMeta{
Name: "MeanReversionV1",
Desc: "VRVP Mean Reversion Strategy",
Input: []types.InputArg{
{Name: "interval", Type: types.InputTypeString, Desc: "Target Interval (e.g., 1m, 1h)", Default: "1m"},
{Name: "period", Type: types.InputTypeInt, Desc: "VRVP calculation window", Default: 100},
{Name: "threshold", Type: types.InputTypeUFloat, Desc: "Reversion Threshold Ratio (e.g. 0.01)", Default: 0.01},
{Name: "buckets", Type: types.InputTypeInt, Desc: "VRVP Buckets", Default: 24},
},
}
}
func (s *MeanReversionV1) Init(input types.Input) (err error) {
s.interval = types.Interval(input.String("interval"))
if _, ok := types.SupportedIntervals[s.interval]; !ok {
s.interval = types.Interval1m
}
s.period = input.Int("period")
if s.period <= 0 {
s.period = 100
}
s.threshold = input.Float("threshold")
s.buckets = input.Int("buckets")
if s.buckets <= 0 {
s.buckets = 24
}
return
}
func (s *MeanReversionV1) CandlePeriods(ctx IIntervalSigStrategyContext) (iss *types.IntervalState[int16]) {
iss = types.NewIntervalState[int16]()
iss.Set(s.interval, int16(s.period))
return
}
func (s *MeanReversionV1) Update(ctx IIntervalSigStrategyContext) (side types.Side) {
// Calculate VRVP period candles
summaryObj := ctx.SummaryIndicator(s.interval, "VRVP", map[string]any{"buckets": s.buckets})
summaryAny, ok := summaryObj.Summary(0, int16(s.period))
if !ok {
return
}
vrvpSummary, ok := summaryAny.(*types.VRVPSummary)
if !ok || vrvpSummary == nil || len(vrvpSummary.Buckets) == 0 {
return
}
// Find POC (Point of Control) - Bucket with max volume
var maxVol float64
var pocPrice float64
found := false
for _, bucket := range vrvpSummary.Buckets {
if bucket.Volume > maxVol {
maxVol = bucket.Volume
pocPrice = bucket.Price
found = true
}
}
if !found {
return
}
// Get Current Price
k := ctx.Get(s.interval, 0)
currentPrice := k.CloseF64()
// Deviation ratio
if pocPrice <= 0 {
return
}
deviation := (currentPrice - pocPrice) / pocPrice
if deviation > s.threshold {
// 当前价格高于 POC, 预期回落
side = types.SideShort
} else if deviation < -s.threshold {
// 当前价格低于 POC, 预期回升
side = types.SideLong
}
return
}