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 }