TODO: 做hash持久化和搜索出正确的策略
This commit is contained in:
parent
a333376c57
commit
5e85a3fe2d
46
base.go
46
base.go
|
@ -3,23 +3,33 @@ package moneymoney
|
|||
import (
|
||||
"context"
|
||||
"encoding/gob"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/474420502/random"
|
||||
"github.com/474420502/structure/compare"
|
||||
"github.com/474420502/structure/tree/treelist"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func GetAll() (result *treelist.Tree[int64]) {
|
||||
const 亿 = 100000000
|
||||
|
||||
result = treelist.New[int64](compare.Any[int64])
|
||||
var stocks []*Stock
|
||||
|
||||
cur, err := cstock.Find(context.TODO(), bson.M{})
|
||||
func GetDate(date string) time.Time {
|
||||
ts, err := time.ParseInLocation("2006-01-02", date, time.Local)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
type StockTree *treelist.Tree[int64, *Stock]
|
||||
|
||||
func GetAll() (result *treelist.Tree[int64, *treelist.Tree[int64, *Stock]]) {
|
||||
|
||||
result = treelist.New[int64, *treelist.Tree[int64, *Stock]](compare.Any[int64])
|
||||
var stocks []*Stock
|
||||
|
||||
f, err := os.Open("./stocks.gob")
|
||||
if err == nil {
|
||||
|
@ -36,6 +46,11 @@ func GetAll() (result *treelist.Tree[int64]) {
|
|||
defer f.Close()
|
||||
|
||||
} else {
|
||||
cur, err := cstock.Find(cxt, bson.M{})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
for cur.Next(context.TODO()) {
|
||||
var s Stock
|
||||
err := cur.Decode(&s)
|
||||
|
@ -66,16 +81,16 @@ func GetAll() (result *treelist.Tree[int64]) {
|
|||
}
|
||||
|
||||
for _, s := range stocks {
|
||||
var daymap *treelist.Tree[int64]
|
||||
var daymap *treelist.Tree[int64, *Stock]
|
||||
idaymap, ok := result.Get(s.Date.Unix())
|
||||
|
||||
// daymap, ok := DateStocks[s.Date.Unix()]
|
||||
if !ok {
|
||||
idaymap = treelist.New(compare.Any[int64])
|
||||
idaymap = treelist.New[int64, *Stock](compare.Any[int64])
|
||||
result.Put(s.Date.Unix(), idaymap)
|
||||
// DateStocks[s.Date.Unix()] = daymap
|
||||
}
|
||||
daymap = idaymap.(*treelist.Tree[int64])
|
||||
daymap = idaymap
|
||||
daymap.Put(s.Code, s)
|
||||
}
|
||||
|
||||
|
@ -85,3 +100,18 @@ func GetAll() (result *treelist.Tree[int64]) {
|
|||
func AggregateNewField(result []*Stock) {
|
||||
|
||||
}
|
||||
|
||||
func ShowSelectStocks(selectStocks []*Stock) {
|
||||
for _, s := range selectStocks {
|
||||
log.Printf("%s %s 当前价格:%f", s.Date.Local().Format("2006-01-02"), s.Name, s.ClosingPrice)
|
||||
// log.Println(s.UpsDownsRatio, s)
|
||||
}
|
||||
}
|
||||
|
||||
func RandomRange[T float32 | float64 | int | int64 | uint32 | uint64](rd *random.Random, rv *RangeValue[T]) {
|
||||
rv.Min = rv.MinLimt + T(rd.Int63n(int64((rv.MaxLimit-rv.MinLimt)/rv.Step)))*rv.Step
|
||||
rv.Max = rv.MinLimt + T(rd.Int63n(int64((rv.MaxLimit-rv.MinLimt)/rv.Step)))*rv.Step
|
||||
if rv.Min > rv.Max {
|
||||
rv.Min, rv.Max = rv.Max, rv.Min
|
||||
}
|
||||
}
|
||||
|
|
7
go.mod
7
go.mod
|
@ -9,11 +9,10 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/474420502/classify v1.3.1
|
||||
github.com/474420502/structure v1.0.1
|
||||
github.com/474420502/structure v1.0.4
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/klauspost/compress v1.13.6
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.0.2 // indirect
|
||||
|
@ -28,7 +27,9 @@ require (
|
|||
|
||||
require (
|
||||
github.com/474420502/gcurl v0.5.1
|
||||
github.com/474420502/random v0.5.2-0.20220222044003-09d6ed40ca23
|
||||
github.com/474420502/requests v1.11.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
golang.org/x/net v0.0.0-20211105192438-b53810dc28af // indirect
|
||||
|
|
7
go.sum
7
go.sum
|
@ -1,12 +1,11 @@
|
|||
github.com/474420502/classify v1.3.1 h1:AakdyoS97lx54uiPjbtTFCyeYr16qebE+ScDvtZmXDA=
|
||||
github.com/474420502/classify v1.3.1/go.mod h1:Z2nPKjdgsxx7P1UfJZOiQdvZqlxlxGYgNswdVz1LYsM=
|
||||
github.com/474420502/gcurl v0.5.1 h1:Rpl0qdffIwgzOivc4BAn8biOpoGIFhOBAFe8vogswIk=
|
||||
github.com/474420502/gcurl v0.5.1/go.mod h1:bYc/86ynsx28WNFd6MDt/8gy0xRvuqhspmEqEm7Sybo=
|
||||
github.com/474420502/random v0.5.2-0.20220222044003-09d6ed40ca23 h1:ZO9oDeD8EOHiHbFLPlZ5WyfF0uBoYfRD0/NoEIFUeAQ=
|
||||
github.com/474420502/random v0.5.2-0.20220222044003-09d6ed40ca23/go.mod h1:51QVTqbWTDUBTA+4phZZjjVsJXWz0zayPTdDEBu+2sA=
|
||||
github.com/474420502/requests v1.11.1 h1:BLI95klIGRjTLeQ7U7CJLkkniVsL2tK0PLJnUTSTyfY=
|
||||
github.com/474420502/requests v1.11.1/go.mod h1:epMXb90Z7hmiOu+hMLFj8eFbkqOXWThNDYHuh2ThTlE=
|
||||
github.com/474420502/structure v1.0.1 h1:X8hM0m6CA+13HZI2/Uv3pO+Kce3cm/ZGfXVeE+S4uN8=
|
||||
github.com/474420502/structure v1.0.1/go.mod h1:rND3ZSiZH84JKV43+bR0/iUHvLlhkcBmW9hyUNkr3bU=
|
||||
github.com/474420502/structure v1.0.4 h1:sHu7Z+4tu2gvPE/ZgYb258/sVOZ1g2jHI0M8TO/DCAk=
|
||||
github.com/474420502/structure v1.0.4/go.mod h1:rND3ZSiZH84JKV43+bR0/iUHvLlhkcBmW9hyUNkr3bU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
|
15
main.go
15
main.go
|
@ -25,6 +25,7 @@ import (
|
|||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
@ -71,17 +72,27 @@ func GetDefaultPage() *rod.Page {
|
|||
|
||||
var client *mongo.Client
|
||||
var cstock *mongo.Collection
|
||||
var DateStocks *treelist.Tree[int64]
|
||||
var DateStocks *treelist.Tree[int64, *treelist.Tree[int64, *Stock]]
|
||||
var CountedDays map[int]bool
|
||||
var err error
|
||||
|
||||
var cxt context.Context
|
||||
var cancel context.CancelFunc
|
||||
|
||||
func init() {
|
||||
log.SetFlags(log.Llongfile | log.LstdFlags)
|
||||
|
||||
client, err = mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://localhost:27017"))
|
||||
cxt, cancel = context.WithTimeout(context.TODO(), time.Second*10)
|
||||
defer cancel()
|
||||
client, err = mongo.Connect(cxt, options.Client().ApplyURI("mongodb://localhost:27017"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
client.Ping(cxt, &readpref.ReadPref{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cstock = client.Database("money").Collection("stock")
|
||||
DateStocks = GetAll()
|
||||
CountedDays = map[int]bool{}
|
||||
|
|
254
main_test.go
254
main_test.go
|
@ -2,220 +2,92 @@ package moneymoney
|
|||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/474420502/structure/tree/treelist"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
)
|
||||
|
||||
const 亿 = 100000000
|
||||
|
||||
func GetDate(date string) time.Time {
|
||||
ts, err := time.ParseInLocation("2006-01-02", date, time.Local)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
func GetStocksByCondition(cday time.Time) []*Stock {
|
||||
var stocks []*Stock
|
||||
|
||||
// cday := GetDate(CurrentDay)
|
||||
start := cday.Add(-time.Hour * 24 * 14)
|
||||
log.Println("重新从", start.Local().Format("2006-01-02"), cday.Local().Format("2006-01-02"), "策略选股")
|
||||
|
||||
// istartStock, _ := DateStocks.Get(start.Unix())
|
||||
siter := DateStocks.Iterator()
|
||||
siter.SeekGE(start.Unix())
|
||||
siter.Valid()
|
||||
{
|
||||
ssiter := siter.Value().(*treelist.Tree[int64]).Iterator()
|
||||
ssiter.SeekToFirst()
|
||||
// ss := ssiter.Value().(*Stock)
|
||||
// log.Printf("%s", ss.Date.Local().Format("2006-01-02"))
|
||||
}
|
||||
|
||||
iter := DateStocks.Iterator()
|
||||
|
||||
// log.Println(iter.SeekLE(cday.Unix()), iter.Valid())
|
||||
iter.SeekLE(cday.Unix())
|
||||
endStock := iter.Value().(*treelist.Tree[int64])
|
||||
|
||||
// log.Println(DateStocks.Size(), endStock.Size())
|
||||
|
||||
endStock.Traverse(func(s *treelist.Slice[int64]) bool {
|
||||
var ok bool
|
||||
citer := siter.Clone()
|
||||
|
||||
stock := s.Value.(*Stock)
|
||||
if stock.MarketValue <= 100*亿 {
|
||||
return true
|
||||
}
|
||||
|
||||
startStock := citer.Value().(*treelist.Tree[int64])
|
||||
|
||||
var istock any
|
||||
for {
|
||||
istock, ok = startStock.Get(stock.Code)
|
||||
if ok {
|
||||
break
|
||||
}
|
||||
citer.Next()
|
||||
if !citer.Valid() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fstock := istock.(*Stock)
|
||||
if fstock.ClosingPrice == 0 {
|
||||
return true
|
||||
}
|
||||
if stock.ClosingPrice == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
stock.MinPrice = fstock.ClosingPrice
|
||||
stock.MaxPrice = stock.ClosingPrice
|
||||
|
||||
stock.UpsDownsRatio = ((stock.ClosingPrice - fstock.ClosingPrice) / fstock.ClosingPrice)
|
||||
// log.Println(stock.UpsDownsRatio, s)
|
||||
|
||||
stocks = append(stocks, stock)
|
||||
return true
|
||||
})
|
||||
|
||||
sort.Slice(stocks, func(i, j int) bool {
|
||||
return stocks[i].UpsDownsRatio < stocks[j].UpsDownsRatio
|
||||
})
|
||||
|
||||
return stocks
|
||||
}
|
||||
|
||||
func TestMoney(t *testing.T) {
|
||||
|
||||
var money float64 = 1000000.0
|
||||
cday := GetDate("2017-04-01")
|
||||
|
||||
ALL_LOOP:
|
||||
for money < 1000000*3 {
|
||||
|
||||
selectStocks := GetStocksByCondition(cday)
|
||||
// log.Println(len(selectStocks))
|
||||
|
||||
for _, s := range selectStocks[0:15] {
|
||||
log.Printf("%.4f%% %s %s %f", s.UpsDownsRatio*100.0, s.Date.Local().Format("2006-01-02"), s.Name, s.ClosingPrice)
|
||||
// log.Println(s.UpsDownsRatio, s)
|
||||
}
|
||||
|
||||
selectStocks = selectStocks[0:15]
|
||||
|
||||
start := (len(selectStocks) - 10) / 2
|
||||
selectStocks = selectStocks[start : start+10]
|
||||
// for _, s := range selectStocks {
|
||||
// log.Printf("%.4f%% %s", s.UpsDownsRatio*100.0, s.Name)
|
||||
// }
|
||||
// TODO: 测试 收益
|
||||
iter := DateStocks.Iterator()
|
||||
iter.SeekGT(cday.Unix())
|
||||
if !iter.Valid() {
|
||||
break
|
||||
}
|
||||
|
||||
for {
|
||||
var total float64 = 0.0
|
||||
iter.Next()
|
||||
|
||||
if !iter.Valid() {
|
||||
break ALL_LOOP
|
||||
}
|
||||
cstocks := iter.Value().(*treelist.Tree[int64])
|
||||
|
||||
var cs *Stock
|
||||
for _, s := range selectStocks {
|
||||
itf, ok := cstocks.Get(s.Code)
|
||||
if ok {
|
||||
cs = itf.(*Stock)
|
||||
total += (cs.ClosingPrice - s.ClosingPrice) / s.ClosingPrice
|
||||
// log.Printf("%.2f", (cs.ClosingPrice-s.ClosingPrice)/s.ClosingPrice)
|
||||
}
|
||||
}
|
||||
|
||||
csdate := cs.Date.Local().Format("2006-01-02")
|
||||
if csdate == "2017-12-07" {
|
||||
for _, s := range selectStocks {
|
||||
log.Printf("%.4f%% %s %s %f %f %f", s.UpsDownsRatio*100.0, s.Date.Local().Format("2006-01-02"), s.Name, s.ClosingPrice, s.MinPrice, s.MaxPrice)
|
||||
// log.Println(s.UpsDownsRatio, s)
|
||||
}
|
||||
log.Println()
|
||||
}
|
||||
|
||||
total = total / float64(len(selectStocks))
|
||||
|
||||
log.Printf("%s 总收益:%.2f%%", csdate, total*100)
|
||||
if total >= 0.10 || total <= -0.20 {
|
||||
money = money + money*total
|
||||
cday = cs.Date
|
||||
log.Printf("最后总财富 1000000 -> money: %f", money)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("最后总财富 1000000 -> money: %f", money)
|
||||
|
||||
HistoryRun()
|
||||
}
|
||||
|
||||
// 统计历史关系参数.
|
||||
func TestCase3(t *testing.T) {
|
||||
cday := GetDate("2017-04-01")
|
||||
cday := GetDate("2017-04-15")
|
||||
citer := DateStocks.Iterator()
|
||||
citer.SeekToFirst()
|
||||
citer.SeekGE(cday.Unix())
|
||||
|
||||
for citer.Valid() {
|
||||
|
||||
stocks := citer.Value().(*treelist.Tree[int64])
|
||||
|
||||
todayIter := stocks.Iterator()
|
||||
stocks := citer.Value()
|
||||
todayIter := stocks.Iterator() // 获取当天 所有股票的迭代器
|
||||
|
||||
cmpiter := citer.Clone()
|
||||
|
||||
var i = 0
|
||||
|
||||
// 向前移动的天数
|
||||
// 向后移动的天数
|
||||
for cmpiter.Valid() {
|
||||
|
||||
todayIter.SeekToFirst()
|
||||
cmpday := cmpiter.Value().(*treelist.Tree[int64])
|
||||
cmpday := cmpiter.Value()
|
||||
|
||||
for todayIter.Valid() {
|
||||
stocks.Traverse(func(s *treelist.Slice[int64, *Stock]) bool {
|
||||
|
||||
s := todayIter.Value().(*Stock)
|
||||
todaystock := s.Value
|
||||
if todaystock.Extend == nil {
|
||||
todaystock.Extend = &StockExtend{
|
||||
MaxPriceDays: 0,
|
||||
MinPriceDays: 100000000000,
|
||||
}
|
||||
todaystock.Extend.UpsDownsRatioDays = append(todaystock.Extend.UpsDownsRatioDays, &UpsDownsDays{})
|
||||
}
|
||||
|
||||
ic, ok := cmpday.Get(s.Code)
|
||||
// 根据股票代码 获取对比的股票
|
||||
c, ok := cmpday.Get(todaystock.Code)
|
||||
if ok {
|
||||
c := ic.(*Stock)
|
||||
if c.Extend == nil {
|
||||
c.Extend = &StockExtend{}
|
||||
}
|
||||
// 满足相邻天数的处理
|
||||
if len(c.Extend.UpsDownsRatioDays) == 0 {
|
||||
if _, ok := CountedDays[i]; ok {
|
||||
UpsDownsRatioDays := ((c.ClosingPrice - s.ClosingPrice) / c.ClosingPrice)
|
||||
c.Extend.UpsDownsRatioDays = append(c.Extend.UpsDownsRatioDays, UpsDownsRatioDays)
|
||||
}
|
||||
|
||||
// 对比的历史前移时间股票
|
||||
var ClosingPrice float64 = 0
|
||||
|
||||
if c.ClosingPrice == 0 {
|
||||
ClosingPrice = c.PreviousClosingPrice
|
||||
} else {
|
||||
ClosingPrice = c.ClosingPrice
|
||||
}
|
||||
|
||||
// TODO: 其他的统计处理
|
||||
if ClosingPrice != 0 {
|
||||
if ClosingPrice > todaystock.Extend.MaxPriceDays {
|
||||
todaystock.Extend.MaxPriceDays = ClosingPrice
|
||||
}
|
||||
|
||||
if ClosingPrice < todaystock.Extend.MinPriceDays {
|
||||
todaystock.Extend.MinPriceDays = ClosingPrice
|
||||
}
|
||||
|
||||
// 满足相邻天数的处理
|
||||
|
||||
// TODO: 其他的统计处理
|
||||
}
|
||||
|
||||
last := todaystock.Extend.UpsDownsRatioDays[len(todaystock.Extend.UpsDownsRatioDays)-1]
|
||||
last.DownsCount++
|
||||
last.UpsCount++
|
||||
if _, ok := CountedDays[i]; ok {
|
||||
last.Ratio = ((ClosingPrice - todaystock.ClosingPrice) / ClosingPrice)
|
||||
todaystock.Extend.UpsDownsRatioDays = append(todaystock.Extend.UpsDownsRatioDays, &UpsDownsDays{
|
||||
UpsCount: last.UpsCount,
|
||||
DownsCount: last.DownsCount,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
todayIter.Next()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if i >= 1<<7 {
|
||||
break
|
||||
|
@ -224,21 +96,33 @@ func TestCase3(t *testing.T) {
|
|||
cmpiter.Prev()
|
||||
i++
|
||||
}
|
||||
|
||||
todayIter.SeekToFirst()
|
||||
for todayIter.Valid() {
|
||||
s := todayIter.Value()
|
||||
if s.Extend != nil {
|
||||
// if len(s.Extend.UpsDownsRatioDays) <= 1 {
|
||||
// log.Println(s.Name, s.Date.Local().String(), s.Code)
|
||||
// }
|
||||
s.Extend.UpsDownsRatioDays = s.Extend.UpsDownsRatioDays[0 : len(s.Extend.UpsDownsRatioDays)-1]
|
||||
}
|
||||
todayIter.Next()
|
||||
}
|
||||
|
||||
citer.Next()
|
||||
}
|
||||
|
||||
var stocks []*Stock
|
||||
DateStocks.Traverse(func(s *treelist.Slice[int64]) bool {
|
||||
s.Value.(*treelist.Tree[int64]).Traverse(func(s *treelist.Slice[int64]) bool {
|
||||
stocks = append(stocks, s.Value.(*Stock))
|
||||
|
||||
DateStocks.Traverse(func(s *treelist.Slice[int64, *treelist.Tree[int64, *Stock]]) bool {
|
||||
s.Value.Traverse(func(s *treelist.Slice[int64, *Stock]) bool {
|
||||
stocks = append(stocks, s.Value)
|
||||
return true
|
||||
})
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if stocks != nil {
|
||||
|
||||
f, err := os.OpenFile("./stocks1.gob", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
225
test_histroy.go
Normal file
225
test_histroy.go
Normal file
|
@ -0,0 +1,225 @@
|
|||
package moneymoney
|
||||
|
||||
import (
|
||||
"hash"
|
||||
"log"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/474420502/random"
|
||||
"github.com/474420502/structure/tree/treelist"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
func HistoryRun() {
|
||||
|
||||
rd := random.New()
|
||||
|
||||
var money float64 = 1000000.0
|
||||
cday := GetDate("2017-05-01")
|
||||
|
||||
p := &Policy{
|
||||
MarketValue: &RangeValue[float64]{MinLimt: 10, MaxLimit: 20000, Step: 1},
|
||||
UpsDownsRatioDays: []*RangeValue[float64]{{MinLimt: 0, MaxLimit: 0.2, Step: 0.01}, {MinLimt: 0, MaxLimit: 0.3, Step: 0.01}, {MinLimt: 0, MaxLimit: 0.5, Step: 0.01}, {MinLimt: 0, MaxLimit: 0.5, Step: 0.01}},
|
||||
UpsCount: &RangeValue[int]{MinLimt: 0, MaxLimit: 100, Step: 1},
|
||||
DownsCount: &RangeValue[int]{MinLimt: 0, MaxLimit: 100, Step: 1},
|
||||
MaxPriceRatio: &RangeValue[float64]{MinLimt: 0, MaxLimit: 1, Step: 0.01},
|
||||
MinPriceRatio: &RangeValue[float64]{MinLimt: 0, MaxLimit: 1, Step: 0.01},
|
||||
}
|
||||
|
||||
RESET:
|
||||
for {
|
||||
|
||||
RandomRange(rd, p.MarketValue)
|
||||
for _, rv := range p.UpsDownsRatioDays {
|
||||
RandomRange(rd, rv)
|
||||
}
|
||||
RandomRange(rd, p.UpsCount)
|
||||
RandomRange(rd, p.DownsCount)
|
||||
RandomRange(rd, p.MaxPriceRatio)
|
||||
RandomRange(rd, p.MinPriceRatio)
|
||||
spew.Println(p)
|
||||
|
||||
ALL_LOOP:
|
||||
for {
|
||||
// log.Println(p)
|
||||
|
||||
selectStocks := GetStocksByCondition(cday, p)
|
||||
// log.Println(len(selectStocks))
|
||||
|
||||
if len(selectStocks) == 0 {
|
||||
cday = cday.Add(time.Hour * 24)
|
||||
if cday.After(GetDate("2022-07-02")) {
|
||||
cday = GetDate("2017-05-01")
|
||||
money = 1000000.0
|
||||
continue RESET
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if len(selectStocks) >= 15 {
|
||||
selectStocks = selectStocks[3:13]
|
||||
}
|
||||
|
||||
// ShowSelectStocks(selectStocks)
|
||||
|
||||
// TODO: 测试 收益
|
||||
iter := DateStocks.Iterator()
|
||||
iter.SeekGT(cday.Unix())
|
||||
if !iter.Valid() {
|
||||
break
|
||||
}
|
||||
|
||||
for {
|
||||
var total float64 = 0.0
|
||||
iter.Next()
|
||||
|
||||
if !iter.Valid() {
|
||||
break ALL_LOOP
|
||||
}
|
||||
cstocks := iter.Value() // 当天的股票数据
|
||||
|
||||
// 当前股票
|
||||
var cs *Stock
|
||||
|
||||
for _, s := range selectStocks {
|
||||
itf, ok := cstocks.Get(s.Code)
|
||||
if ok {
|
||||
cs = itf
|
||||
var ClosePrice float64
|
||||
if cs.ClosingPrice == 0 {
|
||||
ClosePrice = cs.PreviousClosingPrice
|
||||
} else {
|
||||
ClosePrice = cs.ClosingPrice
|
||||
}
|
||||
total += (ClosePrice - s.ClosingPrice) / s.ClosingPrice
|
||||
// log.Printf("%.2f", (cs.ClosingPrice-s.ClosingPrice)/s.ClosingPrice)
|
||||
}
|
||||
}
|
||||
|
||||
total = total / float64(len(selectStocks))
|
||||
|
||||
// log.Printf("%s 总收益: money: %f, 涨跌幅:%.2f%%", cs.Date.Local().Format("2006-01-02"), money+money*total, total*100)
|
||||
if total >= 0.08 || total <= -0.08 {
|
||||
|
||||
for _, s := range selectStocks {
|
||||
show, ok := cstocks.Get(s.Code) // 当前股票
|
||||
if ok {
|
||||
log.Printf("%s %s 买入:%f 当前:%f", s.Date.Local().Format("2006-01-02"), s.Name, s.ClosingPrice, show.ClosingPrice)
|
||||
}
|
||||
}
|
||||
|
||||
money = money + money*total
|
||||
cday = cs.Date
|
||||
log.Printf("最后总财富 1000000 -> money: %f, 涨跌幅: %.2f%%", money, (money-1000000)/1000000*100)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("最后总财富 本金:1000000 -> money: %f, 涨跌幅: %.2f%%", money, (money-1000000)/1000000*100)
|
||||
}
|
||||
}
|
||||
|
||||
type RangeValue[T float32 | float64 | int | int64 | uint32 | uint64] struct {
|
||||
Min T
|
||||
MinLimt T
|
||||
Max T
|
||||
MaxLimit T
|
||||
Step T
|
||||
}
|
||||
|
||||
func (rv *RangeValue[T]) In(v T) bool {
|
||||
return v >= rv.Min && v <= rv.Max
|
||||
}
|
||||
|
||||
type Policy struct {
|
||||
Hash hash.Hash
|
||||
MarketValue *RangeValue[float64]
|
||||
UpsDownsRatioDays []*RangeValue[float64]
|
||||
UpsCount *RangeValue[int]
|
||||
DownsCount *RangeValue[int]
|
||||
MaxPriceRatio *RangeValue[float64]
|
||||
MinPriceRatio *RangeValue[float64]
|
||||
}
|
||||
|
||||
func GetStocksByCondition(cday time.Time, policy *Policy) []*Stock {
|
||||
var stocks []*Stock
|
||||
|
||||
// cday := GetDate(CurrentDay)
|
||||
|
||||
// log.Println("重新从", cday.Local().Format("2006-01-02"), "策略选股")
|
||||
|
||||
iter := DateStocks.Iterator()
|
||||
|
||||
// log.Println(iter.SeekLE(cday.Unix()), iter.Valid())
|
||||
iter.SeekGE(cday.Unix())
|
||||
if !iter.Valid() {
|
||||
return nil
|
||||
}
|
||||
endStock := iter.Value()
|
||||
|
||||
// log.Println(DateStocks.Size(), endStock.Size())
|
||||
|
||||
endStock.Traverse(func(s *treelist.Slice[int64, *Stock]) bool {
|
||||
|
||||
stock := s.Value
|
||||
if stock.Name[0] == '*' {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(stock.Extend.UpsDownsRatioDays) < 4 {
|
||||
return true
|
||||
}
|
||||
|
||||
// if !(stock.MarketValue >= 50*亿) {
|
||||
// return true
|
||||
// }
|
||||
|
||||
if !(policy.MarketValue.In(stock.MarketValue / 亿)) {
|
||||
return true
|
||||
}
|
||||
|
||||
udDays := stock.Extend.UpsDownsRatioDays
|
||||
// if !(udDays[0].Ratio < -0.02 && udDays[3].Ratio > 0.03) {
|
||||
// return true
|
||||
// }
|
||||
|
||||
for i, ratio := range policy.UpsDownsRatioDays {
|
||||
if !ratio.In(udDays[i].Ratio) {
|
||||
return true
|
||||
}
|
||||
if !policy.UpsCount.In(udDays[i].UpsCount) {
|
||||
return true
|
||||
}
|
||||
if !policy.DownsCount.In(udDays[i].DownsCount) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
maxRatio := (stock.Extend.MaxPriceDays - stock.ClosingPrice) / stock.ClosingPrice
|
||||
if !policy.MaxPriceRatio.In(maxRatio) {
|
||||
return true
|
||||
}
|
||||
|
||||
minRatio := (stock.ClosingPrice - stock.Extend.MinPriceDays) / stock.ClosingPrice
|
||||
if !policy.MaxPriceRatio.In(minRatio) {
|
||||
return true
|
||||
}
|
||||
|
||||
if stock.ClosingPrice == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
// log.Println(stock.UpsDownsRatio, s)
|
||||
|
||||
stocks = append(stocks, stock)
|
||||
return true
|
||||
})
|
||||
|
||||
sort.Slice(stocks, func(i, j int) bool {
|
||||
return stocks[i].UpsDownsRatio < stocks[j].UpsDownsRatio
|
||||
})
|
||||
|
||||
return stocks
|
||||
}
|
12
unity.go
12
unity.go
|
@ -39,10 +39,16 @@ type Stock struct {
|
|||
Extend *StockExtend `json:"Extend" bson:"Extend"`
|
||||
}
|
||||
|
||||
type UpsDownsDays struct {
|
||||
Ratio float64 `json:"Ratio" bson:"Ratio"`
|
||||
UpsCount int `json:"UpCount" bson:"UpsCount"`
|
||||
DownsCount int `json:"DownCount" bson:"DownsCount"`
|
||||
}
|
||||
|
||||
type StockExtend struct {
|
||||
UpsDownsRatioDays []float64 `json:"UpsDownsRatioDays" bson:"UpsDownsRatioDays"`
|
||||
MaxPriceDays float64 `json:"MaxPriceDays" bson:"MaxPriceDays"`
|
||||
MinPriceDay float64 `json:"MinPriceDay" bson:"MinPriceDay"`
|
||||
UpsDownsRatioDays []*UpsDownsDays `json:"UpsDownsRatioDays" bson:"UpsDownsRatioDays"`
|
||||
MaxPriceDays float64 `json:"MaxPriceDays" bson:"MaxPriceDays"`
|
||||
MinPriceDays float64 `json:"MinPriceDays" bson:"MinPriceDays"`
|
||||
}
|
||||
|
||||
type StockBase struct {
|
||||
|
|
Loading…
Reference in New Issue
Block a user