-
Notifications
You must be signed in to change notification settings - Fork 9
Open
Description
Implement indicator code
You can use GPT to help quickly implement the banta version of the indicator based on the existing logic !
For example, you can use the following prompt words (including go code):
type Kline struct {
Time int64
Open float64
High float64
Low float64
Close float64
Volume float64
Info float64
}
type BarEnv struct {
TimeStart int64
TimeStop int64
Exchange string
MarketType string
Symbol string
TimeFrame string
TFMSecs int64 //周期的毫秒间隔
BarNum int
MaxCache int
VNum int
Open *Series
High *Series
Low *Series
Close *Series
Volume *Series
Info *Series
Data map[string]interface{}
}
type Series struct {
ID int
Env *BarEnv
Data []float64
Cols []*Series
Time int64
More interface{}
Subs map[string]map[int]*Series // 由此序列派生的;function:hash:object
XLogs map[int]*CrossLog // 此序列交叉记录
}
func (e *BarEnv) OnBar(barMs int64, open, high, low, close, volume, info float64) {
if e.TimeStop > barMs {
panic(fmt.Errorf("%s/%s old Bar Receive: %d, Current: %d", e.Symbol, e.TimeFrame, barMs, e.TimeStop))
}
e.TimeStart = barMs
e.TimeStop = barMs + e.TFMSecs
e.BarNum += 1
if e.Open == nil {
e.Open = e.NewSeries([]float64{open})
e.High = e.NewSeries([]float64{high})
e.Low = e.NewSeries([]float64{low})
e.Close = e.NewSeries([]float64{close})
e.Volume = e.NewSeries([]float64{volume})
e.Info = e.NewSeries([]float64{info})
if e.MaxCache == 0 {
// 默认保留1000个
e.MaxCache = 1000
}
} else {
e.Open.Time = barMs
e.Open.Data = append(e.Open.Data, open)
e.High.Time = barMs
e.High.Data = append(e.High.Data, high)
e.Low.Time = barMs
e.Low.Data = append(e.Low.Data, low)
e.Close.Time = barMs
e.Close.Data = append(e.Close.Data, close)
e.Volume.Time = barMs
e.Volume.Data = append(e.Volume.Data, volume)
e.Info.Time = barMs
e.Info.Data = append(e.Info.Data, info)
}
}
func (e *BarEnv) NewSeries(data []float64) *Series {
subs := make(map[string]map[int]*Series)
xlogs := make(map[int]*CrossLog)
res := &Series{e.VNum, e, data, nil, e.TimeStart, nil, subs, xlogs}
e.VNum += 1
return res
}
func (s *Series) Set(obj interface{}) *Series {
if !s.Cached() {
return s.Append(obj)
}
return s
}
func (s *Series) Append(obj interface{}) *Series {
if s.Time >= s.Env.TimeStop {
panic(fmt.Sprintf("repeat append on Series, %s, %v -> %v",
s.Env.Symbol, s.Time, s.Env.TimeStop))
}
s.Time = s.Env.TimeStop
if val, ok := obj.(float64); ok {
s.Data = append(s.Data, val)
} else if val, ok := obj.(int); ok {
s.Data = append(s.Data, float64(val))
} else if arr, ok := obj.([]float64); ok {
for i, v := range arr {
if i >= len(s.Cols) {
col := s.To("_", i)
s.Cols = append(s.Cols, col)
col.Append(v)
} else {
col := s.Cols[i]
col.Append(v)
}
}
} else if cols, ok := obj.([]*Series); ok {
s.Cols = cols
} else {
fmt.Printf("invalid val for Series.Append: %t", obj)
panic(ErrInvalidSeriesVal)
}
return s
}
func (s *Series) Cached() bool {
return s.Time >= s.Env.TimeStop
}
func (s *Series) Get(i int) float64 {
if len(s.Cols) > 0 {
panic(fmt.Errorf("Get Val on Merged Series!"))
}
allLen := len(s.Data)
if i < 0 || i >= allLen {
return math.NaN()
}
return s.Data[allLen-i-1]
}
/*
Range 获取范围内的值。
start 起始位置,0是最近的
stop 结束位置,不含
*/
func (s *Series) Range(start, stop int) []float64 {
allLen := len(s.Data)
_start := max(allLen-stop, 0)
_stop := min(allLen-start, allLen)
if _start >= _stop {
return []float64{}
}
res := s.Data[_start:_stop]
tmp := make([]float64, len(res))
copy(tmp, res)
slices.Reverse(tmp)
return tmp
}
func (s *Series) Len() int {
if len(s.Cols) > 0 {
return s.Cols[0].Len()
}
return len(s.Data)
}
func (s *Series) Cut(keepNum int) {
for _, dv := range s.Subs {
for _, v := range dv {
v.Cut(keepNum)
}
}
if len(s.Cols) > 0 {
for _, col := range s.Cols {
col.Cut(keepNum)
}
return
}
curLen := len(s.Data)
if curLen <= keepNum {
return
}
s.Data = s.Data[curLen-keepNum:]
}
func (s *Series) Back(num int) *Series {
res := s.To("_back", num)
if !res.Cached() {
endPos := len(s.Data) - num
if endPos > 0 {
res.Data = s.Data[:endPos]
} else {
res.Data = nil
}
res.Time = s.Env.TimeStop
}
return res
}
func (s *Series) objVal(rel string, obj interface{}) (*Series, float64) {
if ser, ok := obj.(*Series); ok {
return s.To(rel, ser.ID), ser.Get(0)
} else if intVal, ok := obj.(int); ok {
return s.To(rel, intVal), float64(intVal)
} else if flt32Val, ok := obj.(float32); ok {
return s.To(rel, int(flt32Val*10)), float64(flt32Val)
} else if fltVal, ok := obj.(float64); ok {
return s.To(rel, int(fltVal*10)), fltVal
} else {
fmt.Printf("invalid val for Series.objVal: %t", obj)
panic(ErrInvalidSeriesVal)
}
}
func (s *Series) To(k string, v int) *Series {
sub, _ := s.Subs[k]
if sub == nil {
sub = make(map[int]*Series)
s.Subs[k] = sub
}
old, _ := sub[v]
if old == nil {
old = s.Env.NewSeries(nil)
sub[v] = old
}
return old
}
type tnrState struct {
arr []float64
sumVal float64
}
// TNR Trend to Noise Ratio
func TNR(obj *Series, period int) *Series {
res := obj.To("_tnr", period)
if res.Cached() {
return res
}
curVal := math.Abs(obj.Get(0) - obj.Get(1))
sta, _ := res.More.(*tnrState)
if sta == nil {
sta = &tnrState{}
res.More = sta
}
var resVal = math.NaN()
if math.IsNaN(curVal) {
sta.arr = make([]float64, 0)
sta.sumVal = 0
} else {
sta.sumVal += curVal
if len(sta.arr) < period {
sta.arr = append(sta.arr, curVal)
} else {
sta.sumVal -= sta.arr[0]
sta.arr = append(sta.arr[1:], curVal)
if sta.sumVal > 0 {
diffVal := math.Abs(obj.Get(0) - obj.Get(period))
resVal = diffVal / sta.sumVal
}
}
}
return res.Append(resVal)
}
// KAMABy Kaufman Adaptive Moving Average
func KAMABy(obj *Series, period int, fast, slow float64) *Series {
res := obj.To("_kama", period)
if res.Cached() {
return res
}
var prevMa = math.NaN()
if cacheVal, ok := res.More.(*float64); ok {
prevMa = *cacheVal
}
effRatio := TNR(obj, period).Get(0)
smoothing := math.Pow(effRatio*(fast-slow)+slow, 2)
curVal := obj.Get(0)
if math.IsNaN(prevMa) {
prevMa = curVal // Initialize with the first price value
} else {
prevMa += smoothing * (curVal - prevMa)
}
res.More = &prevMa
return res.Append(prevMa)
}
//其他已实现的go指标如下,为减少上下文长度,只列出函数签名,实现其他方法时,尽可能引用已有方法减少代码冗余
func AvgPrice(e *BarEnv) *Series // AvgPrice 平均价格=(h+l+c)/3
func Sum(obj *Series, period int) *Series // Sum of period n
func SMA(obj *Series, period int) *Series // simple moving average of period n
func VWMA(price *Series, vol *Series, period int) *Series // VWMA 成交量加权平均价格 公式:sum(price*volume)/sum(volume)
func EMA(obj *Series, period int) *Series // EMA 指数移动均线 最近一个权重:2/(n+1)
/* EMABy 指数移动均线
最近一个权重:2/(n+1)
initType:0使用SMA初始化,1第一个有效值初始化
*/
func EMABy(obj *Series, period int, initType int) *Series
/*
RMA 相对移动均线
和EMA区别是:分子分母都减一
最近一个权重:1/n
*/
func RMA(obj *Series, period int) *Series
/*RMABy 相对移动均线
和EMA区别是:分子分母都减一
最近一个权重:1/n
initType:0使用SMA初始化,1第一个有效值初始化
initVal 默认Nan
*/
func RMABy(obj *Series, period int, initType int, initVal float64) *Series
func TR(high *Series, low *Series, close *Series) *Series
func ATR(high *Series, low *Series, close *Series, period int) *Series
/* MACD 计算MACD指标。
国外主流使用init_type=0,MyTT和国内主要使用init_type=1*/
func MACD(obj *Series, fast int, slow int, smooth int) *Series
func MACDBy(obj *Series, fast int, slow int, smooth int, initType int) *Series
func RSI(obj *Series, period int) *Series // RSI 计算相对强度指数
func Highest(obj *Series, period int) *Series
func HighestBar(obj *Series, period int) *Series
func Lowest(obj *Series, period int) *Series
func LowestBar(obj *Series, period int) *Series
func KDJ(high *Series, low *Series, close *Series, period int, sm1 int, sm2 int) *Series // KDJ 也称为:Stoch随机指标。返回k, d
func KDJBy(high *Series, low *Series, close *Series, period int, sm1 int, sm2 int, maBy string) *Series
/* Aroon 阿隆指标 反映了一段时间内出现最高价和最低价距离当前时间的远近。
AroonUp: (period - HighestBar(high, period+1)) / period * 100
AroonDn: (period - LowestBar(low, period+1)) / period * 100
Osc: AroonUp - AroonDn
返回:AroonUp, Osc, AroonDn*/
func Aroon(high *Series, low *Series, period int) *Series
/* StdDev 计算标准差和均值
返回:stddev,mean*/
func StdDev(obj *Series, period int) *Series
func BBANDS(obj *Series, period int, stdUp, stdDn float64) *Series // BBANDS 布林带指标。返回:upper, mean, lower
/* TD 计算Tom DeMark Sequence(狄马克序列)
9和13表示超买;-9和-13表示超卖*/
func TD(obj *Series) *Series
func ROC(obj *Series, period int) *Series // ROC rate of change
func AvgDev(obj *Series, period int) *Series // AvgDev sum(abs(Vi - mean))/period
func CCI(obj *Series, period int) *Series // CCI Commodity Channel Index
func CMF(env *BarEnv, period int) *Series // CMF Chaikin Money Flow
func MFV(env *BarEnv) (float64, float64)
func ADL(env *BarEnv) *Series // ADL Chaikin Accumulation/Distribution
func ChaikinOsc(env *BarEnv, short int, long int) *SeriesAs mentioned above, some indicators in Go are implemented, as well as the calculation logic of ADX (pinescript code of ADX). Please help me implement the ADX indicator in Go.
Test indicator correctness
You can add a CaseItem to the end of sta_inds_test.go:TestCommon to observe the output of the new indicator.
Then you can add calls to other libraries of this indicator in the scripts/test_inds.py script and compare the outputs after execution.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels