From 9beedad1086bc32703c28338b73919918c80421a Mon Sep 17 00:00:00 2001 From: strange Date: Tue, 24 Feb 2026 11:06:43 +0800 Subject: [PATCH] vrvp strategy --- config/exchange.toml | 4 +- internal/trading/sig/indicator_context.go | 5 ++ pkg/strategy/mean_reversion_v1.go | 92 +++++++++++++++++------ pkg/strategy/sig_strategy.go | 4 + pkg/strategy/sig_strategy_registry.go | 1 + 5 files changed, 79 insertions(+), 27 deletions(-) diff --git a/config/exchange.toml b/config/exchange.toml index a88552b..baa2cab 100644 --- a/config/exchange.toml +++ b/config/exchange.toml @@ -18,9 +18,9 @@ receiveBuffer = 4096 marketSubscribeLimit = 16 consumeBatch = 1024 consumeLater = 2000 # 时间到达later或者数据累计到batch触发consume -# httpProxy = "" +httpProxy = "" # httpProxy = "http://192.168.1.4:7890" -httpProxy = "http://10.255.183.209:7890" +# httpProxy = "http://10.255.183.209:7890" # 模拟盘API交易地址如下: # REST:https://www.okx.com diff --git a/internal/trading/sig/indicator_context.go b/internal/trading/sig/indicator_context.go index c4270e3..3be6988 100644 --- a/internal/trading/sig/indicator_context.go +++ b/internal/trading/sig/indicator_context.go @@ -173,6 +173,11 @@ func (c *IndicatorContext) SummaryIndicator(name string, args ...any) (summary i } func matchIndicatorArgs(args ...any) (input types.Input) { + defer func() { + if input == nil { + input = make(types.Input) + } + }() inputLoop: for _, arg := range args { switch v := arg.(type) { diff --git a/pkg/strategy/mean_reversion_v1.go b/pkg/strategy/mean_reversion_v1.go index 5b58b16..06a5ca2 100644 --- a/pkg/strategy/mean_reversion_v1.go +++ b/pkg/strategy/mean_reversion_v1.go @@ -1,16 +1,16 @@ package strategy import ( - "math" "sig-pub/pkg/types" - "sig-pub/pkg/zlog" ) // MeanReversionV1 type MeanReversionV1 struct { IIntervalSigStrategy - rate float64 - rate2 float64 + interval types.Interval + period int + threshold float64 + buckets int } func (s *MeanReversionV1) New() ISigStrategy { @@ -20,44 +20,86 @@ func (s *MeanReversionV1) New() ISigStrategy { func (s *MeanReversionV1) Meta() StrategyMeta { return StrategyMeta{ Name: "MeanReversionV1", - Desc: "均值回归策略v1", + Desc: "VRVP Mean Reversion Strategy", Input: []types.InputArg{ - {Name: "rate", Type: types.InputTypeUFloat, Desc: "上线影线与基线比例"}, - {Name: "rate2", Type: types.InputTypeUFloat, Desc: "上线影线之间比例"}, + {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.rate = input.Float("rate") - s.rate2 = input.Float("rate2") +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(types.Interval5m, 1) - iss.Set(types.Interval15m, 2) - iss.Set(types.Interval30m, 2) + iss.Set(s.interval, int16(s.period)) return } func (s *MeanReversionV1) Update(ctx IIntervalSigStrategyContext) (side types.Side) { - // O 109744.8 H 110600 L 109507.5 C 109686.8 - k0 := ctx.Get("5m", 0) - open, close, high, low := k0.OpenF64(), k0.CloseF64(), k0.HighF64(), k0.LowF64() - base := math.Abs(open - close) - rup := (high - max(open, close)) / base - rdown := (min(open, close) - low) / base + // 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 + } - if k0.Ts == 1761833700000 { - zlog.Debugf("base=%.4f, rup=%.4f, rdown=%.4f", base, rup, rdown) + vrvpSummary, ok := summaryAny.(*types.VRVPSummary) + if !ok || vrvpSummary == nil || len(vrvpSummary.Buckets) == 0 { + return } - if rup > s.rate && rup/rdown > s.rate2 { - return types.SideLong + + // 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 rdown > s.rate && rdown/rup > s.rate2 { - return types.SideShort + + 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 } diff --git a/pkg/strategy/sig_strategy.go b/pkg/strategy/sig_strategy.go index 9f47a3a..4a315cb 100644 --- a/pkg/strategy/sig_strategy.go +++ b/pkg/strategy/sig_strategy.go @@ -58,6 +58,8 @@ type IIntervalSigStrategyContext interface { Series(interval types.Interval, offset, count int16) (klines types.Klines) // 获取窗口类型指标 Indicator(interval types.Interval, name string, args ...any) indicator.IIndicatorSeries + // SummaryIndicator 获取Summary类型指标 + SummaryIndicator(interval types.Interval, name string, args ...any) indicator.IIndicatorSummary } // 多币种多周期策略接口 @@ -77,4 +79,6 @@ type IInstanceIntervalSigStrategyContext interface { Series(instId string, interval types.Interval, offset, count int16) (klines types.Klines) // 获取窗口类型指标 Indicator(instId string, interval types.Interval, name string, args ...any) indicator.IIndicatorSeries + // SummaryIndicator 获取Summary类型指标 + SummaryIndicator(instId string, interval types.Interval, name string, args ...any) indicator.IIndicatorSummary } diff --git a/pkg/strategy/sig_strategy_registry.go b/pkg/strategy/sig_strategy_registry.go index 77438cc..4f75a54 100644 --- a/pkg/strategy/sig_strategy_registry.go +++ b/pkg/strategy/sig_strategy_registry.go @@ -31,6 +31,7 @@ func (r *SigStrategyRegistry) Init() (err error) { r.MustRegistStrategy(&TrendTrackV1{}) r.MustRegistStrategy(&Grid{}) r.MustRegistStrategy(&BollGrid{}) + r.MustRegistStrategy(&MeanReversionV1{}) return }