成功测试策略

This commit is contained in:
eson 2022-07-03 08:38:06 +08:00
parent 04fec33a01
commit 239b30d716
8 changed files with 353 additions and 55 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
*.json *.json
*.random_base_data
stocks.gob

4
api.go
View File

@ -12,10 +12,10 @@ func GetFromAPI() {
for _, code := range GetStocks() { for _, code := range GetStocks() {
if code.MCAP >= 200*100000000 { if code.MCAP >= 100*100000000 {
pcode.StringSet(code.CODE) pcode.StringSet(code.CODE)
start.StringSet("20150101") start.StringSet("20150101")
end.StringSet("20220622") end.StringSet("20220701")
resp, err := tp.Execute() resp, err := tp.Execute()
if err != nil { if err != nil {

71
base.go Normal file
View File

@ -0,0 +1,71 @@
package moneymoney
import (
"context"
"encoding/gob"
"os"
"github.com/474420502/structure/compare"
"github.com/474420502/structure/tree/treelist"
"go.mongodb.org/mongo-driver/bson"
)
func GetAll() (result *treelist.Tree[int64]) {
result = treelist.New[int64](compare.Any[int64])
var stocks []*Stock
cur, err := cstock.Find(context.TODO(), bson.M{})
if err != nil {
panic(err)
}
f, err := os.Open("./stocks.gob")
if err == nil {
err = gob.NewDecoder(f).Decode(&stocks)
if err != nil {
panic(err)
}
} else {
for cur.Next(context.TODO()) {
var s Stock
err := cur.Decode(&s)
if err != nil {
panic(err)
}
stocks = append(stocks, &s)
// result = append(result, &s)
}
f, err = os.OpenFile("./stocks.gob", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
if err != nil {
panic(err)
}
err = gob.NewEncoder(f).Encode(stocks)
if err != nil {
panic(err)
}
}
for _, s := range stocks {
var daymap *treelist.Tree[int64]
idaymap, ok := result.Get(s.Date.Unix())
// daymap, ok := DateStocks[s.Date.Unix()]
if !ok {
idaymap = treelist.New(compare.Any[int64])
result.Put(s.Date.Unix(), idaymap)
// DateStocks[s.Date.Unix()] = daymap
}
daymap = idaymap.(*treelist.Tree[int64])
daymap.Put(s.Code, s)
}
return
}
func AggregateNewField(result []*Stock) {
}

2
go.mod
View File

@ -9,6 +9,8 @@ require (
) )
require ( require (
github.com/474420502/classify v1.3.1
github.com/474420502/structure v1.0.1
github.com/go-stack/stack v1.8.0 // indirect github.com/go-stack/stack v1.8.0 // indirect
github.com/golang/snappy v0.0.1 // indirect github.com/golang/snappy v0.0.1 // indirect
github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/compress v1.13.6 // indirect

5
go.sum
View File

@ -1,7 +1,12 @@
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 h1:Rpl0qdffIwgzOivc4BAn8biOpoGIFhOBAFe8vogswIk=
github.com/474420502/gcurl v0.5.1/go.mod h1:bYc/86ynsx28WNFd6MDt/8gy0xRvuqhspmEqEm7Sybo= 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/requests v1.11.1 h1:BLI95klIGRjTLeQ7U7CJLkkniVsL2tK0PLJnUTSTyfY= github.com/474420502/requests v1.11.1 h1:BLI95klIGRjTLeQ7U7CJLkkniVsL2tK0PLJnUTSTyfY=
github.com/474420502/requests v1.11.1/go.mod h1:epMXb90Z7hmiOu+hMLFj8eFbkqOXWThNDYHuh2ThTlE= 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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

68
main.go
View File

@ -16,6 +16,7 @@ import (
"time" "time"
"github.com/474420502/gcurl" "github.com/474420502/gcurl"
"github.com/474420502/structure/tree/treelist"
"github.com/go-rod/rod" "github.com/go-rod/rod"
"github.com/go-rod/rod/lib/devices" "github.com/go-rod/rod/lib/devices"
"github.com/go-rod/rod/lib/launcher" "github.com/go-rod/rod/lib/launcher"
@ -28,55 +29,6 @@ import (
"golang.org/x/text/transform" "golang.org/x/text/transform"
) )
type Stock struct {
Date string `json:"日期" bson:"日期"`
CodeStr string `json:"股票代码" bson:"股票代码"`
Name string `json:"名称" bson:"名称"`
ClosingPrice float64 `json:"收盘价" bson:"收盘价"`
MaxPrice float64 `json:"最高价" bson:"最高价"`
MinPrice float64 `json:"最低价" bson:"最低价"`
OpeningPrice float64 `json:"开盘价" bson:"开盘价"`
PreviousClosingPrice float64 `json:"前收盘" bson:"前收盘"`
UpsDowns float64 `json:"涨跌额" bson:"涨跌额"`
UpsDownsRatio float64 `json:"涨跌幅" bson:"涨跌幅"`
TurnoverRate float64 `json:"换手率" bson:"换手率"`
Volume float64 `json:"成交量" bson:"成交量"`
Turnover float64 `json:"成交金额" bson:"成交金额"`
MarketValue float64 `json:"总市值" bson:"总市值"`
CirculatingMarketValue float64 `json:"流通市值" bson:"流通市值"`
Code int64 `json:"股票数字代码" bson:"股票数字代码"`
}
type StockBase struct {
// CodeStr string // 代地区码
// Code string // 不带地区码
CODE string `json:"CODE"`
FIVE_MINUTE float64 `json:"FIVE_MINUTE"`
HIGH float64 `json:"HIGH"`
HS float64 `json:"HS"`
LB float64 `json:"LB"`
LOW float64 `json:"LOW"`
MCAP float64 `json:"MCAP"`
MFSUM float64 `json:"MFSUM"`
NAME string `json:"NAME"`
OPEN float64 `json:"OPEN"`
PE float64 `json:"PE"`
PERCENT float64 `json:"PERCENT"`
PRICE float64 `json:"PRICE"`
SNAME string `json:"SNAME"`
SYMBOL string `json:"SYMBOL"`
TCAP float64 `json:"TCAP"`
TURNOVER float64 `json:"TURNOVER"`
UPDOWN float64 `json:"UPDOWN"`
VOLUME float64 `json:"VOLUME"`
WB float64 `json:"WB"`
YESTCLOSE float64 `json:"YESTCLOSE"`
ZF float64 `json:"ZF"`
NO float64 `json:"NO"`
}
var DefaultPage *rod.Page var DefaultPage *rod.Page
func GetDefaultPage() *rod.Page { func GetDefaultPage() *rod.Page {
@ -118,6 +70,8 @@ func GetDefaultPage() *rod.Page {
} }
var client *mongo.Client var client *mongo.Client
var cstock *mongo.Collection
var DateStocks *treelist.Tree[int64]
var err error var err error
func init() { func init() {
@ -127,6 +81,8 @@ func init() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
cstock = client.Database("money").Collection("stock")
DateStocks = GetAll()
} }
func main() { func main() {
@ -323,8 +279,13 @@ func DownloadDataFromCode(code *StockBase) {
panic(err) panic(err)
} }
ts, err := time.ParseInLocation("2006-01-02", fields[0], time.Local)
if err != nil {
panic(err)
}
s := &Stock{ s := &Stock{
Date: fields[0], Date: ts,
CodeStr: fields[1], CodeStr: fields[1],
Name: fields[2], Name: fields[2],
ClosingPrice: ToFloat(fields[3]), ClosingPrice: ToFloat(fields[3]),
@ -386,8 +347,13 @@ func SaveFromCSV(downloaddata []byte) {
panic(err) panic(err)
} }
ts, err := time.ParseInLocation("2006-01-02", fields[0], time.Local)
if err != nil {
panic(err)
}
s := &Stock{ s := &Stock{
Date: fields[0], Date: ts,
CodeStr: fields[1], CodeStr: fields[1],
Name: fields[2], Name: fields[2],
ClosingPrice: ToFloat(fields[3]), ClosingPrice: ToFloat(fields[3]),

View File

@ -1,9 +1,194 @@
package moneymoney package moneymoney
import "testing" import (
"log"
"sort"
"testing"
"time"
"github.com/474420502/structure/tree/treelist"
)
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
}
var CurrentDay = "2017-03-15"
func GetStocksByCondition(cday time.Time) []*Stock {
var stocks []*Stock
// cday := GetDate(CurrentDay)
start := cday.Add(-time.Hour * 24 * 14)
log.Println(start.Local(), cday.Local())
// cur, err := cstock.Find(context.TODO(), bson.M{
// "日期": bson.M{"$gte": start, "$lte": cday},
// // "涨跌幅": bson.M{"$gte": -15.0, "$lte": -2.0},
// // // "换手率": bson.M{"$gte": 1.0},
// // "流通市值": bson.M{"$gte": 100 * 亿},
// })
// if err != nil {
// panic(err)
// }
// log.Println(cur.Current)
// // var total = 0.0
// var stocks []*Stock
// for cur.Next(context.TODO()) {
// var s Stock
// err := cur.Decode(&s)
// if err != nil {
// panic(err)
// }
// // clf.Add(&s)
// var daymap *treelist.Tree[int64]
// idaymap, ok := DateStocks.Get(s.Date.Unix())
// // daymap, ok := DateStocks[s.Date.Unix()]
// if !ok {
// idaymap = treelist.New(compare.Any[int64])
// DateStocks.Put(s.Date.Unix(), idaymap)
// // DateStocks[s.Date.Unix()] = daymap
// }
// daymap = idaymap.(*treelist.Tree[int64])
// daymap.Put(s.Code, &s)
// }
// 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())
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 = 0.0
cday := GetDate("2017-05-15")
for money < 1.0 {
selectStocks := GetStocksByCondition(cday)
log.Println(len(selectStocks))
for _, s := range selectStocks[0:15] {
log.Printf("%.4f%% %s %s %f %f", s.UpsDownsRatio*100.0, s.Date.Local().Format("2006-01-02"), s.Name, s.MinPrice, s.MaxPrice)
// 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())
for {
var total float64 = 0.0
iter.Next()
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)
}
}
total = total / float64(len(selectStocks))
log.Printf("%.2f%%, %s", total*100, cs.Date.Local())
if total >= 0.06 {
money += total
cday = cs.Date
break
}
}
}
}
func TestCase3(t *testing.T) {
}
func TestCase2(t *testing.T) { func TestCase2(t *testing.T) {
GetFromAPI() GetFromAPI() // 获取基础数据
} }
func TestCase1(t *testing.T) { func TestCase1(t *testing.T) {

67
unity.go Normal file
View File

@ -0,0 +1,67 @@
package moneymoney
import "time"
type Stock struct {
// 日期
Date time.Time `json:"日期" bson:"日期"`
// 股票代码
CodeStr string `json:"股票代码" bson:"股票代码"`
// 名称
Name string `json:"名称" bson:"名称"`
// 收盘价
ClosingPrice float64 `json:"收盘价" bson:"收盘价"`
// 最高价
MaxPrice float64 `json:"最高价" bson:"最高价"`
// 最低价
MinPrice float64 `json:"最低价" bson:"最低价"`
// 开盘价
OpeningPrice float64 `json:"开盘价" bson:"开盘价"`
// 前收盘
PreviousClosingPrice float64 `json:"前收盘" bson:"前收盘"`
// 涨跌额
UpsDowns float64 `json:"涨跌额" bson:"涨跌额"`
// 涨跌幅
UpsDownsRatio float64 `json:"涨跌幅" bson:"涨跌幅"`
// 换手率
TurnoverRate float64 `json:"换手率" bson:"换手率"`
// 成交量
Volume float64 `json:"成交量" bson:"成交量"`
// 成交金额
Turnover float64 `json:"成交金额" bson:"成交金额"`
// 总市值
MarketValue float64 `json:"总市值" bson:"总市值"`
// 流通市值
CirculatingMarketValue float64 `json:"流通市值" bson:"流通市值"`
// 股票数字代码
Code int64 `json:"股票数字代码" bson:"股票数字代码"`
}
type StockBase struct {
// CodeStr string // 代地区码
// Code string // 不带地区码
CODE string `json:"CODE"`
FIVE_MINUTE float64 `json:"FIVE_MINUTE"`
HIGH float64 `json:"HIGH"`
HS float64 `json:"HS"`
LB float64 `json:"LB"`
LOW float64 `json:"LOW"`
MCAP float64 `json:"MCAP"`
MFSUM float64 `json:"MFSUM"`
NAME string `json:"NAME"`
OPEN float64 `json:"OPEN"`
PE float64 `json:"PE"`
PERCENT float64 `json:"PERCENT"`
PRICE float64 `json:"PRICE"`
SNAME string `json:"SNAME"`
SYMBOL string `json:"SYMBOL"`
TCAP float64 `json:"TCAP"`
TURNOVER float64 `json:"TURNOVER"`
UPDOWN float64 `json:"UPDOWN"`
VOLUME float64 `json:"VOLUME"`
WB float64 `json:"WB"`
YESTCLOSE float64 `json:"YESTCLOSE"`
ZF float64 `json:"ZF"`
NO float64 `json:"NO"`
}