deving
This commit is contained in:
@@ -55,5 +55,13 @@ func RuleFilter(basic *models.StockBasic) (bool, string) {
|
|||||||
if re := rule.NewAmount().Run(basic.TsCode); re.Score <= 0 {
|
if re := rule.NewAmount().Run(basic.TsCode); re.Score <= 0 {
|
||||||
return false, re.Desc
|
return false, re.Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if re := rule.NewRoe().Run(basic.TsCode); re.Score <= 0 {
|
||||||
|
return false, re.Desc
|
||||||
|
}
|
||||||
|
|
||||||
|
if re := rule.NewRsi(strategy.GetArgs(basic.TsCode)).Run(basic.TsCode); re.Score <= 0 {
|
||||||
|
return false, re.Desc
|
||||||
|
}
|
||||||
return true, ""
|
return true, ""
|
||||||
}
|
}
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -61,6 +61,7 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/markcheno/go-talib v0.0.0-20250114000313-ec55a20c902f
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -98,6 +98,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/markcheno/go-talib v0.0.0-20250114000313-ec55a20c902f h1:iKq//xEUUaeRoXNcAshpK4W8eSm7HtgI0aNznWtX7lk=
|
||||||
|
github.com/markcheno/go-talib v0.0.0-20250114000313-ec55a20c902f/go.mod h1:3YUtoVrKWu2ql+iAeRyepSz3fy6a+19hJzGS88+u4u0=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ func GetIndustry() (industry []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func GetArgs(code string) *models.StockArgs {
|
||||||
|
var args models.StockArgs
|
||||||
|
err := impl.DBService.Where("ts_code = ?", code).First(&args).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &args
|
||||||
|
}
|
||||||
|
|
||||||
func GetBasic(code string) *models.StockBasic {
|
func GetBasic(code string) *models.StockBasic {
|
||||||
var data StockData
|
var data StockData
|
||||||
impl.DBService.Where("ts_code = ?", code).First(&data.Basic)
|
impl.DBService.Where("ts_code = ?", code).First(&data.Basic)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
MinRoe = 0
|
MinRoe float64 = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
type Roe struct {
|
type Roe struct {
|
||||||
@@ -26,20 +26,15 @@ func NewRoe() *Roe {
|
|||||||
|
|
||||||
func (r *Roe) Run(code string) *types.RuleResult {
|
func (r *Roe) Run(code string) *types.RuleResult {
|
||||||
|
|
||||||
var data []models.StockDaily
|
var data models.StockFinaIndicator
|
||||||
impl.DBService.Where("ts_code = ?", code).Order("trade_date desc").Limit(LastDay).Find(&data)
|
err := impl.DBService.Where("ts_code = ?", code).Order("period desc").Limit(1).First(&data).Error
|
||||||
|
if err != nil {
|
||||||
check := true
|
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: "最近无财报,无ROE值!"}
|
||||||
for _, row := range data {
|
|
||||||
if row.Close < MinPrice {
|
|
||||||
check = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !check {
|
if data.Roe < MinRoe {
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: fmt.Sprintf("最近%d天, 有价格低于%.2f", LastDay, MinPrice)}
|
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: fmt.Sprintf("ROE=%.2f 低于%.2f", data.Roe, MinRoe)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: 1, Desc: fmt.Sprintf("最近%d天, 价格均高于%.2f", LastDay, MinPrice)}
|
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: 1, Desc: fmt.Sprintf("ROE=%.2f 高于%.2f", data.Roe, MinRoe)}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,69 @@
|
|||||||
package rule
|
package rule
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.apinb.com/quant/gostock/internal/impl"
|
||||||
|
"git.apinb.com/quant/gostock/internal/logic/types"
|
||||||
|
"git.apinb.com/quant/gostock/internal/models"
|
||||||
|
talib "github.com/markcheno/go-talib"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Rsi struct {
|
||||||
|
Key string
|
||||||
|
Name string
|
||||||
|
Conf *StockArgConf
|
||||||
|
Args *models.StockArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
type StockArgConf struct {
|
||||||
|
BestByDrawdown string `json:"best_by_drawdown"`
|
||||||
|
BestByProfit string `json:"best_by_profit"`
|
||||||
|
BestByReturn string `json:"best_by_return"`
|
||||||
|
BestBySharpe string `json:"best_by_sharpe"`
|
||||||
|
BestByWinRate string `json:"best_by_win_rate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRsi(args *models.StockArgs) *Rsi {
|
||||||
|
var conf StockArgConf
|
||||||
|
err := json.Unmarshal([]byte(args.Config), &conf)
|
||||||
|
if err != nil {
|
||||||
|
return &Rsi{
|
||||||
|
Key: "Rsi",
|
||||||
|
Name: "RSI指标",
|
||||||
|
Conf: nil,
|
||||||
|
Args: args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Rsi{
|
||||||
|
Key: "Rsi",
|
||||||
|
Name: "RSI指标",
|
||||||
|
Conf: &conf,
|
||||||
|
Args: args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rsi) Run(code string) *types.RuleResult {
|
||||||
|
if r.Conf == nil {
|
||||||
|
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: "参数错误!"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Conf.BestByProfit != "rsi" {
|
||||||
|
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: "BestByProfit!=RSI,BestByProfit=" + r.Conf.BestByProfit}
|
||||||
|
}
|
||||||
|
|
||||||
|
var close []float64
|
||||||
|
impl.DBService.Model(models.StockDaily{}).Where("ts_code = ?", code).Order("trade_date desc").Limit(r.Args.RsiPeriod*4).Pluck("close", &close)
|
||||||
|
if len(close) < r.Args.RsiPeriod {
|
||||||
|
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: "数据不足"}
|
||||||
|
}
|
||||||
|
|
||||||
|
rsiResult := talib.Rsi(close, r.Args.RsiPeriod)
|
||||||
|
lastRsi := rsiResult[len(rsiResult)-1]
|
||||||
|
if lastRsi > float64(r.Args.RsiOversold) {
|
||||||
|
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: fmt.Sprintf("RSI=%.2f 高于%d", lastRsi, r.Args.RsiOversold)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: 1, Desc: fmt.Sprintf("RSI=%.2f 低于%d", lastRsi, r.Args.RsiOversold)}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user