deving
This commit is contained in:
@@ -26,12 +26,14 @@ func main() {
|
|||||||
strategy.InitCacheByCode(code)
|
strategy.InitCacheByCode(code)
|
||||||
model := models.NewStratModel("selector", code)
|
model := models.NewStratModel("selector", code)
|
||||||
stratRule := rule.NewRule(model)
|
stratRule := rule.NewRule(model)
|
||||||
|
{
|
||||||
stratRule.RunUpDate(strategy.Cache[code].Basic.ListDate)
|
stratRule.RunUpDate(strategy.Cache[code].Basic.ListDate)
|
||||||
stratRule.RunST(strategy.Cache[code].Basic.Name)
|
stratRule.RunST(strategy.Cache[code].Basic.Name)
|
||||||
stratRule.RunIndustry(strategy.Cache[code].Basic.Industry)
|
stratRule.RunIndustry(strategy.Cache[code].Basic.Industry)
|
||||||
stratRule.RunPrice(code)
|
stratRule.RunPrice(code)
|
||||||
stratRule.RunAmount(code)
|
stratRule.RunAmount(code)
|
||||||
stratRule.RunRoe(code)
|
stratRule.RunRoe(code)
|
||||||
|
}
|
||||||
|
|
||||||
model.Save()
|
model.Save()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package strategy
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.apinb.com/quant/gostock/internal/logic/strategy/rule"
|
|
||||||
"git.apinb.com/quant/gostock/internal/logic/types"
|
"git.apinb.com/quant/gostock/internal/logic/types"
|
||||||
"git.apinb.com/quant/gostock/internal/models"
|
"git.apinb.com/quant/gostock/internal/models"
|
||||||
)
|
)
|
||||||
@@ -33,11 +32,6 @@ func MustFilter(basic *models.StockBasic) (bool, *types.ResultData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ClacFilter(allow []*types.ResultData) []*types.ResultData {
|
func ClacFilter(allow []*types.ResultData) []*types.ResultData {
|
||||||
for idx, item := range allow {
|
|
||||||
re := rule.NewRsi(GetArgs(item.Code)).Run(item.Code)
|
|
||||||
allow[idx].Score = re.Score
|
|
||||||
allow[idx].RSI = re.Result.(float64)
|
|
||||||
}
|
|
||||||
|
|
||||||
return allow
|
return allow
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ func (r *RuleFactory) RunPrice(code string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !check {
|
if !check {
|
||||||
r.Model.GtAmount = -1
|
r.Model.GtPrice = -1
|
||||||
r.Model.AddDesc(fmt.Sprintf("最近%d天, 有价格低于%.2f", LastDay, MinPrice))
|
r.Model.AddDesc(fmt.Sprintf("最近%d天, 有价格低于%.2f", LastDay, MinPrice))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Model.GtAmount = 1
|
r.Model.GtPrice = 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,20 +19,22 @@ func (r *RuleFactory) RunRoe(code string) {
|
|||||||
var data models.StockFinaIndicator
|
var data models.StockFinaIndicator
|
||||||
err := impl.DBService.Where("ts_code = ?", code).Order("period desc").Limit(1).First(&data).Error
|
err := impl.DBService.Where("ts_code = ?", code).Order("period desc").Limit(1).First(&data).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Model.GtAmount = -1
|
r.Model.GtRoe = -1
|
||||||
|
r.Model.ValRoe = -1
|
||||||
r.Model.AddDesc("最近无财报,无ROE值!")
|
r.Model.AddDesc("最近无财报,无ROE值!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Roe = utils.FloatRound(data.Roe, 2)
|
data.Roe = utils.FloatRound(data.Roe, 2)
|
||||||
|
r.Model.ValRoe = data.Roe
|
||||||
|
|
||||||
if data.Roe < MinRoe {
|
if data.Roe < MinRoe {
|
||||||
r.Model.GtAmount = -1
|
r.Model.GtRoe = -1
|
||||||
r.Model.AddDesc(fmt.Sprintf("ROE=%.2f 低于%.2f", data.Roe, MinRoe))
|
r.Model.AddDesc(fmt.Sprintf("ROE=%.2f 低于%.2f", data.Roe, MinRoe))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Model.GtAmount = 1
|
r.Model.GtRoe = 1
|
||||||
r.Model.AddDesc(fmt.Sprintf("ROE=%.2f 高于%.2f", data.Roe, MinRoe))
|
r.Model.AddDesc(fmt.Sprintf("ROE=%.2f 高于%.2f", data.Roe, MinRoe))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,10 @@ import (
|
|||||||
|
|
||||||
"git.apinb.com/bsm-sdk/core/utils"
|
"git.apinb.com/bsm-sdk/core/utils"
|
||||||
"git.apinb.com/quant/gostock/internal/impl"
|
"git.apinb.com/quant/gostock/internal/impl"
|
||||||
"git.apinb.com/quant/gostock/internal/logic/types"
|
|
||||||
"git.apinb.com/quant/gostock/internal/models"
|
"git.apinb.com/quant/gostock/internal/models"
|
||||||
talib "github.com/markcheno/go-talib"
|
talib "github.com/markcheno/go-talib"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Rsi struct {
|
|
||||||
Key string
|
|
||||||
Name string
|
|
||||||
Conf *StockArgConf
|
|
||||||
Args *models.StockArgs
|
|
||||||
}
|
|
||||||
|
|
||||||
type StockArgConf struct {
|
type StockArgConf struct {
|
||||||
BestByDrawdown string `json:"best_by_drawdown"`
|
BestByDrawdown string `json:"best_by_drawdown"`
|
||||||
BestByProfit string `json:"best_by_profit"`
|
BestByProfit string `json:"best_by_profit"`
|
||||||
@@ -26,67 +18,83 @@ type StockArgConf struct {
|
|||||||
BestByWinRate string `json:"best_by_win_rate"`
|
BestByWinRate string `json:"best_by_win_rate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRsi(args *models.StockArgs) *Rsi {
|
func GetArgConfig(code string) (*models.StockArgs, *StockArgConf, error) {
|
||||||
rsi := &Rsi{
|
var args models.StockArgs
|
||||||
Key: "Rsi",
|
err := impl.DBService.Where("ts_code = ?", code).First(&args).Error
|
||||||
Name: "RSI指标",
|
if err != nil {
|
||||||
Conf: nil,
|
return nil, nil, err
|
||||||
Args: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
if args == nil {
|
|
||||||
return rsi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var conf StockArgConf
|
var conf StockArgConf
|
||||||
err := json.Unmarshal([]byte(args.Config), &conf)
|
err = json.Unmarshal([]byte(args.Config), &conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rsi
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rsi.Conf = &conf
|
return &args, &conf, nil
|
||||||
rsi.Args = args
|
|
||||||
return rsi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rsi) Run(code string) *types.RuleResult {
|
func (r *RuleFactory) RunRsi(code string) {
|
||||||
if r.Conf == nil {
|
args, conf, err := GetArgConfig(code)
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: "参数错误!"}
|
if err != nil {
|
||||||
|
r.Model.ScoreRsi = -1
|
||||||
|
r.Model.AddDesc("RSI参数错误!")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Conf.BestByProfit != "rsi" {
|
if conf.BestByProfit != "rsi" {
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: "BestByProfit!=RSI,BestByProfit=" + r.Conf.BestByProfit}
|
r.Model.ScoreRsi = -1
|
||||||
|
r.Model.AddDesc("BestByProfit不是RSI")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var close []float64
|
var close []float64
|
||||||
impl.DBService.Model(models.StockDaily{}).Where("ts_code = ?", code).Order("trade_date desc").Limit(r.Args.RsiPeriod*4).Pluck("close", &close)
|
impl.DBService.Model(models.StockDaily{}).Where("ts_code = ?", code).Order("trade_date desc").Limit(args.RsiPeriod*4).Pluck("close", &close)
|
||||||
if len(close) < r.Args.RsiPeriod {
|
if len(close) < args.RsiPeriod {
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: "数据不足"}
|
r.Model.ScoreRsi = -1
|
||||||
|
r.Model.AddDesc("数据不足")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newCloses := reverseSlice(close)
|
newCloses := reverseSlice(close)
|
||||||
|
|
||||||
rsiResult := talib.Rsi(newCloses, r.Args.RsiPeriod)
|
rsiResult := talib.Rsi(newCloses, args.RsiPeriod)
|
||||||
prveRsi := rsiResult[len(rsiResult)-2]
|
prveRsi := utils.FloatRound(rsiResult[len(rsiResult)-2], 2)
|
||||||
lastRsi := rsiResult[len(rsiResult)-1]
|
lastRsi := utils.FloatRound(rsiResult[len(rsiResult)-1], 2)
|
||||||
lastRsi = utils.FloatRound(lastRsi, 2)
|
r.Model.ValRsiLast = lastRsi
|
||||||
|
r.Model.ValRsiPrve = prveRsi
|
||||||
|
r.Model.ValRsiOversold = args.RsiOversold
|
||||||
prveRsiInt := int(prveRsi)
|
prveRsiInt := int(prveRsi)
|
||||||
lastRsiInt := int(lastRsi)
|
lastRsiInt := int(lastRsi)
|
||||||
|
|
||||||
// 跌破RSI下轨
|
// 跌破RSI下轨
|
||||||
if lastRsiInt > r.Args.RsiOversold {
|
if lastRsiInt > args.RsiOversold {
|
||||||
if CheckLowest(close, lastRsiInt, 14) {
|
if CheckLowest(close, lastRsiInt, 14) {
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: 1, Result: lastRsi, Desc: fmt.Sprintf("RSI=%d 跌破下轨,14日最低", lastRsiInt)}
|
r.Model.ScoreRsi = 1
|
||||||
|
r.Model.AddDesc(fmt.Sprintf("RSI=%d 跌破下轨,14日最低", lastRsiInt))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if CheckLowest(close, lastRsiInt, 20) {
|
if CheckLowest(close, lastRsiInt, 20) {
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: 1, Result: lastRsi, Desc: fmt.Sprintf("RSI=%d 跌破下轨,20日最低", lastRsiInt)}
|
r.Model.ScoreRsi = 1
|
||||||
|
r.Model.AddDesc(fmt.Sprintf("RSI=%d 跌破下轨,20日最低", lastRsiInt))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: fmt.Sprintf("RSI=%d 高于%d", lastRsiInt, r.Args.RsiOversold)}
|
r.Model.ScoreRsi = -1
|
||||||
|
r.Model.AddDesc(fmt.Sprintf("RSI=%d 高于Oversold%d", lastRsiInt, args.RsiOversold))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// RSI跌破下轨后呈上涨趋势
|
// RSI跌破下轨后呈上涨趋势
|
||||||
if lastRsiInt < prveRsiInt {
|
if lastRsiInt < prveRsiInt {
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: -1, Desc: fmt.Sprintf("Rsi=%d prveRsi=%d,跌破下轨,持续下跌", lastRsiInt, prveRsiInt)}
|
r.Model.ScoreRsi = -1
|
||||||
|
r.Model.AddDesc(fmt.Sprintf("Rsi=%d prveRsi=%d,突破下轨,持续下跌", lastRsiInt, prveRsiInt))
|
||||||
|
return
|
||||||
|
} else if lastRsiInt == prveRsiInt {
|
||||||
|
r.Model.ScoreRsi = 1
|
||||||
|
r.Model.AddDesc(fmt.Sprintf("Rsi=%d prveRsi=%d,突破下轨,与前一交易日无太大波动", lastRsiInt, prveRsiInt))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return &types.RuleResult{Key: r.Key, Name: r.Name, Score: 1, Result: lastRsi, Desc: fmt.Sprintf("RSI=%d prveRsi=%d,跌破下轨后呈上涨趋势", lastRsiInt, prveRsiInt)}
|
r.Model.ScoreRsi = 2
|
||||||
|
r.Model.AddDesc(fmt.Sprintf("Rsi=%d prveRsi=%d,突破下轨后呈上涨趋势", lastRsiInt, prveRsiInt))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
24
internal/models/strat_desc.go
Normal file
24
internal/models/strat_desc.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.apinb.com/bsm-sdk/core/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StratDesc struct {
|
||||||
|
ID uint `gorm:"primarykey"`
|
||||||
|
CreatedAt time.Time
|
||||||
|
StratModelID uint `gorm:"column:strat_model_id"`
|
||||||
|
Hash string `gorm:"uniqueIndex"`
|
||||||
|
Desc string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
database.AppendMigrate(&StratDesc{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableName 设置表名
|
||||||
|
func (StratDesc) TableName() string {
|
||||||
|
return "strat_desc"
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.apinb.com/bsm-sdk/core/database"
|
"git.apinb.com/bsm-sdk/core/database"
|
||||||
@@ -21,7 +22,14 @@ type StratModel struct {
|
|||||||
GtAmount int // 每日交易额大于设定值
|
GtAmount int // 每日交易额大于设定值
|
||||||
GtPrice int // 最近20日交易日价格大于设定值
|
GtPrice int // 最近20日交易日价格大于设定值
|
||||||
GtRoe int // ROE 是否大于设定值
|
GtRoe int // ROE 是否大于设定值
|
||||||
Desc string
|
ScoreRsi int
|
||||||
|
|
||||||
|
// 值
|
||||||
|
ValRoe float64
|
||||||
|
ValRsiOversold int
|
||||||
|
ValRsiPrve float64
|
||||||
|
ValRsiLast float64
|
||||||
|
Desc []StratDesc `gorm:"foreignKey:StratModelID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -43,7 +51,17 @@ func NewStratModel(key, code string) *StratModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StratModel) AddDesc(d string) {
|
func (s *StratModel) AddDesc(d string) {
|
||||||
s.Desc = s.Desc + "||" + d
|
hash := utils.Md5(fmt.Sprintf("%s-%d-%s:%s", s.StratKey, s.Ymd, s.Code, d))
|
||||||
|
|
||||||
|
var cnt int64
|
||||||
|
impl.DBService.Model(&StratDesc{}).Where("hash=?", hash).Count(&cnt)
|
||||||
|
if cnt > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.Desc = append(s.Desc, StratDesc{
|
||||||
|
Hash: hash,
|
||||||
|
Desc: d,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StratModel) Save() error {
|
func (s *StratModel) Save() error {
|
||||||
|
|||||||
Reference in New Issue
Block a user