Browse Source

相关性算法

main
strange 9 months ago
parent
commit
142e06d251
  1. 30
      internal/trading/sig/sig_test.go
  2. 41
      pkg/strategy/mul_inst_rank.go
  3. 18
      pkg/strategy/sig_strategy.go
  4. 9
      pkg/strategy/strategy.go
  5. 63
      pkg/types/ta/association.go
  6. 16
      pkg/types/ta/ta.go
  7. 26
      pkg/types/ta/ta_test.go

30
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("."))
}

41
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
}

18
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
}

9
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

63
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 肯德尔相关系数

16
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
}

26
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)
}
Loading…
Cancel
Save