gitee.com/quant1x/engine@v1.8.4/trader/safes.go (about) 1 package trader 2 3 import ( 4 "fmt" 5 "gitee.com/quant1x/engine/cache" 6 "gitee.com/quant1x/exchange" 7 "gitee.com/quant1x/gox/api" 8 "gitee.com/quant1x/gox/concurrent" 9 "gitee.com/quant1x/gox/coroutine" 10 "gitee.com/quant1x/gox/logger" 11 "os" 12 "path" 13 "slices" 14 "strings" 15 "sync" 16 "time" 17 ) 18 19 const ( 20 blacklistFilename = "safes.csv" 21 ) 22 23 // SecureType 安全类型 24 // 25 // 白名单: Pure(纯净), Safe(安全), Trustworthy(值得信赖), Approved(已批准), Acceptable(可接受), Permitted(允许) 26 // 黑名单: Forbidden(禁止), Unsafe(不安全), Untrustworthy(不值得信赖), Rejected(被拒绝), Unacceptable(不可接受), Prohibited(禁止) 27 // 备选: SecureVariety, SecureType, SecureKind 28 type SecureType uint8 29 30 const ( 31 FreeTrading SecureType = iota // 自由交易 32 ProhibitForBuying // 禁止买入 33 ProhibitForSelling // 禁止卖出 34 ProhibitTrading SecureType = 0xff // 禁止交易, 买入和卖出 35 36 //NotForSale SecureType = 16 // 非卖品 37 //NotForBuy SecureType = 86 // 非买品 38 ) 39 40 var ( 41 mapSecureTypes = map[SecureType]string{ 42 FreeTrading: "自由交易", 43 ProhibitForBuying: "禁止买入", 44 ProhibitForSelling: "禁止卖出", 45 ProhibitTrading: "禁止交易", 46 } 47 ) 48 49 func UsageOfSecureType() string { 50 keys := api.Keys(mapSecureTypes) 51 slices.Sort(keys) 52 var builder strings.Builder 53 for _, typ := range keys { 54 desc, _ := mapSecureTypes[typ] 55 builder.WriteString(fmt.Sprintf("%d: %s\n", typ, desc)) 56 } 57 return builder.String() 58 } 59 60 var ( 61 onceSafes coroutine.PeriodicOnce 62 mapSafes = concurrent.NewTreeMap[string, SecureType]() 63 mutexSafes sync.RWMutex 64 //ctxSafes, _ = coroutine.GetContextWithCancel() 65 ) 66 67 // BlackAndWhite 黑白名单 68 type BlackAndWhite struct { 69 Code string `name:"证券代码" dataframe:"code"` 70 Type SecureType `name:"类型" dataframe:"type"` 71 } 72 73 //func notify() { 74 // watcher, err := fsnotify.NewWatcher() 75 // if err != nil { 76 // logger.Error(err) 77 // return 78 // } 79 // defer watcher.Close() 80 //} 81 82 func getFileModTime(filename string) time.Time { 83 fileStat, err := os.Lstat(filename) 84 if err != nil { 85 return time.Now() 86 } 87 return fileStat.ModTime() 88 } 89 90 // 监控黑白名单文件的变化 91 func notifyBlackAndWhiteList() { 92 filename := path.Join(cache.GetRootPath(), blacklistFilename) 93 if !api.FileExist(filename) { 94 _ = api.CheckFilepath(filename, true) 95 _ = os.WriteFile(filename, nil, 0644) 96 } 97 98 lastModTime := getFileModTime(filename) 99 ticker := time.NewTicker(1 * time.Second) 100 defer ticker.Stop() 101 for { 102 select { 103 case <-ticker.C: 104 modTime := getFileModTime(filename) 105 if modTime.After(lastModTime) { 106 logger.Warnf("黑白名单文件有变化, 重新加载...") 107 lazyLoadListOfBlackAndWhite() 108 logger.Warnf("黑白名单文件有变化, 重新加载...OK") 109 lastModTime = modTime 110 } 111 } 112 } 113 } 114 115 func init() { 116 go notifyBlackAndWhiteList() 117 } 118 119 // 加载黑白名单 120 func lazyLoadListOfBlackAndWhite() { 121 mutexSafes.Lock() 122 defer mutexSafes.Unlock() 123 filename := path.Join(cache.GetRootPath(), blacklistFilename) 124 var list []BlackAndWhite 125 err := api.CsvToSlices(filename, &list) 126 if err != nil || len(list) == 0 { 127 return 128 } 129 mapSafes.Clear() 130 for _, v := range list { 131 securityCode := exchange.CorrectSecurityCode(v.Code) 132 mapSafes.Put(securityCode, v.Type) 133 } 134 } 135 136 // SyncLoadListOfBlackAndWhite 同步黑白名单 137 func SyncLoadListOfBlackAndWhite() { 138 mutexSafes.Lock() 139 defer mutexSafes.Unlock() 140 filename := path.Join(cache.GetRootPath(), blacklistFilename) 141 var list []BlackAndWhite 142 mapSafes.Each(func(key string, value SecureType) { 143 if value == FreeTrading { 144 return 145 } 146 list = append(list, BlackAndWhite{Code: key, Type: value}) 147 }) 148 _ = api.SlicesToCsv(filename, list) 149 } 150 151 // 校验和修正证券代码 152 func verify_and_correct_for_security_code(code string) (securityCode string) { 153 onceSafes.Do(lazyLoadListOfBlackAndWhite) 154 return exchange.CorrectSecurityCode(code) 155 } 156 157 // 检查是否禁止的类型 158 func checkNotVarietyType(code string, varietyType SecureType) bool { 159 securityCode := verify_and_correct_for_security_code(code) 160 v, ok := mapSafes.Get(securityCode) 161 if !ok { 162 return true 163 } 164 if v != varietyType && v != ProhibitTrading { 165 return true 166 } 167 return false 168 } 169 170 // AddCodeToBlackList 新增黑白名单成分股 171 func AddCodeToBlackList(code string, secureType SecureType) { 172 _, ok := mapSecureTypes[secureType] 173 if !ok { 174 fmt.Println() 175 } 176 securityCode := verify_and_correct_for_security_code(code) 177 mapSafes.Put(securityCode, secureType) 178 SyncLoadListOfBlackAndWhite() 179 } 180 181 // ProhibitTradingToBlackList 禁止交易 - 双向 182 func ProhibitTradingToBlackList(code string) { 183 AddCodeToBlackList(code, ProhibitTrading) 184 } 185 186 func ProhibitBuyingToBlackList(code string) { 187 AddCodeToBlackList(code, ProhibitForBuying) 188 } 189 190 func ProhibitSellingToBlackList(code string) { 191 AddCodeToBlackList(code, ProhibitForSelling) 192 } 193 194 // CheckForBuy 检查是否可以买 195 func CheckForBuy(code string) bool { 196 return checkNotVarietyType(code, ProhibitForBuying) 197 } 198 199 // CheckForSell 检查是否可卖 200 func CheckForSell(code string) bool { 201 return checkNotVarietyType(code, ProhibitForSelling) 202 }