diff --git a/internal/trading/sig/sig_test.go b/internal/trading/sig/sig_test.go new file mode 100644 index 0000000..960b519 --- /dev/null +++ b/internal/trading/sig/sig_test.go @@ -0,0 +1,30 @@ +package sig + +import ( + "fmt" + "sig-pub/api/pb" + "sig-pub/pkg/types" + "sig-pub/pkg/utils/times" + "testing" +) + +func TestKlineSeries(t *testing.T) { + ks := NewKlineSeries(pb.ExchangeType_SIG, "TEST_USDT", types.Interval5m) + intervalAdder := types.SupportedIntervals[types.Interval5m] + KlineBefore0 := int64(1672502400000) + + w := times.NewWatch() + for i := range int64(128000) { + k := &types.Kline{ + Ts: intervalAdder(KlineBefore0, i), + } + ks.Update(k) + } + fmt.Println(w.ElapsedFmt(".")) + w.Reset() + for range 100000 { + a := ks.MustSeries(0, 12) // 500(op/ms) + _ = a + } + fmt.Println(w.ElapsedFmt(".")) +} diff --git a/pkg/strategy/mul_inst_rank.go b/pkg/strategy/mul_inst_rank.go new file mode 100644 index 0000000..52322a0 --- /dev/null +++ b/pkg/strategy/mul_inst_rank.go @@ -0,0 +1,41 @@ +package strategy + +import ( + "sig-pub/pkg/types" +) + +// 多币种多周期策略 +type MultiInstanceRank struct { + IIntervalSigStrategy + rate float64 + rate2 float64 +} + +func (s *MultiInstanceRank) New() ISigStrategy { + return &MultiInstanceRank{} +} + +func (s *MultiInstanceRank) Meta() StrategyMeta { + return StrategyMeta{ + Name: "MultiInstanceRank", + Desc: "多币种多周期策略", + Input: []types.InputArg{ + {Name: "rate", Type: types.InputTypeUFloat, Desc: "上线影线与基线比例"}, + {Name: "rate2", Type: types.InputTypeUFloat, Desc: "上线影线之间比例"}, + }, + } +} + +func (s *MultiInstanceRank) Init(input types.Input) (err error) { // 校验参数, 并根据参数初始化策略 + s.rate = input.Float("rate") + s.rate2 = input.Float("rate2") + return +} + +func (s *MultiInstanceRank) CandlePeriods(ctx IIntervalSigStrategyContext) (insts []string, iss *types.IntervalState[int16]) { + iss = types.NewIntervalState[int16]() + iss.Set(types.Interval5m, 1) + iss.Set(types.Interval15m, 2) + iss.Set(types.Interval30m, 2) + return +} diff --git a/pkg/strategy/sig_strategy.go b/pkg/strategy/sig_strategy.go index 50724f1..9098b35 100644 --- a/pkg/strategy/sig_strategy.go +++ b/pkg/strategy/sig_strategy.go @@ -56,3 +56,21 @@ type IIntervalSigStrategyContext interface { // 获取窗口类型指标 Indicator(interval types.Interval, name string, args ...any) indicator.IIndicatorSeries } + +// 多币种多周期策略接口 +type IInstanceIntervalSigStrategy interface { + ISigStrategy + CandlePeriods(ctx IIntervalSigStrategyContext) (insts []string, iss *types.IntervalState[int16]) // 需要的各周期最小数据k线数, 回测时用, 若不定义则取最大窗口值 + Update(ctx IIntervalSigStrategyContext) (side types.Side) +} + +type IInstanceIntervalSigStrategyContext interface { + // Input 获取输入参数 + Input() types.Input + // Get [0]当前k线 + Get(instId string, interval types.Interval, offset int16) types.Kline + // Series [offset...end] + Series(instId string, interval types.Interval, offset, count int16) (klines series.Klines) + // 获取窗口类型指标 + Indicator(instId string, interval types.Interval, name string, args ...any) indicator.IIndicatorSeries +} diff --git a/pkg/strategy/strategy.go b/pkg/strategy/strategy.go index 5003e43..6587bc3 100644 --- a/pkg/strategy/strategy.go +++ b/pkg/strategy/strategy.go @@ -12,10 +12,11 @@ import ( type SigStrategyType int32 const ( - _ SigStrategyType = iota - SigStrategyTypeSingle // 单周期单交易所策略 - SigStrategyTypeInterval // 多周期策略 - SigStrategyTypeExchange // 多交易所策略 + _ SigStrategyType = iota + SigStrategyTypeSingle // 单周期策略 + SigStrategyTypeInterval // 多周期策略 + SigStrategyTypeInstance // 多币种策略 + SigStrategyTypeInstanceInterval // 多币种多周期策略 ) type StrategyType int32 diff --git a/pkg/types/ta/association.go b/pkg/types/ta/association.go new file mode 100644 index 0000000..8b24652 --- /dev/null +++ b/pkg/types/ta/association.go @@ -0,0 +1,63 @@ +package ta + +import ( + "fmt" + "math" +) + +// Pearson 计算皮尔逊相关系数 +// 1(完美正相关) 0(无线性相关) -1(完美负相关) +// |r| 接近 1 表示强相关, 接近 0 表示弱相关 +// 如果数据近似正态且线性, 适合平稳市场线性走势; 易受极端事件影响 +func Pearson(series1, series2 []float64) (r float64, err error) { + length := len(series1) + if length < 2 || length != len(series2) { + err = fmt.Errorf("pearson series1 and series2 length not equal") + return + } + avg1 := Avg(series1) + avg2 := Avg(series2) + + var pd_sum, xd_sum, yd_sum float64 + for i := range length { + d1 := series1[i] - avg1 + d2 := series2[i] - avg2 + xd_sum += d1 * d1 + yd_sum += d2 * d2 + pd_sum += d1 * d2 + } + r = pd_sum / (math.Sqrt(xd_sum) * math.Sqrt(yd_sum)) + return +} + +// Spearman 斯皮尔曼相关系数, 针对秩顺序的皮尔逊 +// 适合波动剧烈市场(如 BTC 牛熊转换);捕捉整体趋势一致性 +// 在之前的 BTC/ETH/SOL 示例中,Spearman 值略高于 Pearson,表明价格走势有单调一致性,但存在非线性因素(如 SOL 的爆发性增长)。 +func Spearman(series1, series2 []float64) (r float64, err error) { + length := len(series1) + if length < 2 || length != len(series2) { + err = fmt.Errorf("spearman series1 and series2 length not equal") + return + } + sort1 := make([]float64, length) + sort2 := make([]float64, length) + for i := range length { + sort1[i] = float64(i + 1) + sort2[i] = float64(i + 1) + } + sortFn := func(series []float64, sorts []float64) { + for i := range series { + for j := i + 1; j < length; j++ { + if series[i] > series[j] { + series[i], series[j] = series[j], series[i] + sorts[i], sorts[j] = sorts[j], sorts[i] + } + } + } + } + sortFn(series1, sort1) + sortFn(series2, sort2) + return Pearson(sort1, sort2) +} + +// Kendall 肯德尔相关系数 diff --git a/pkg/types/ta/ta.go b/pkg/types/ta/ta.go new file mode 100644 index 0000000..e7cb805 --- /dev/null +++ b/pkg/types/ta/ta.go @@ -0,0 +1,16 @@ +package ta + +func Avg(series []float64) (r float64) { + length := len(series) + if length == 0 { + return + } + return Sum(series) / float64(length) +} + +func Sum(series []float64) (r float64) { + for _, v := range series { + r += v + } + return +} diff --git a/pkg/types/ta/ta_test.go b/pkg/types/ta/ta_test.go new file mode 100644 index 0000000..a012512 --- /dev/null +++ b/pkg/types/ta/ta_test.go @@ -0,0 +1,26 @@ +package ta + +import ( + "fmt" + "testing" +) + +func TestPearson(t *testing.T) { + s1 := []float64{1, 2, 3, 4} + s2 := []float64{2, 4, 6, 8} + s3 := []float64{8, 6, 4, 2} + r, _ := Pearson(s1, s2) // 0.999 完美正相关 + fmt.Println(r) + r, _ = Pearson(s1, s3) // -0.999 完美负相关 + fmt.Println(r) + +} + +func TestSpearman(t *testing.T) { + x := []float64{10, 20, 30, 40, 50} + y := []float64{15, 25, 20, 45, 50} + r, _ := Spearman(x, y) + fmt.Println(r) + r, _ = Pearson(x, y) + fmt.Println(r) +}