feat: 自动候选筛选与股票研究工作台

This commit is contained in:
2026-10-09 20:39:23 +08:00
parent 92329ddce2
commit 57882ff568
32 changed files with 1343 additions and 87 deletions
+7 -2
View File
@@ -99,6 +99,7 @@ func serve(ctx context.Context, c config.Config, logger *zap.Logger) error {
var strategyRepo service.StrategyRepository
var backtestRepo service.BacktestRepository
var marketRepo service.MarketRepository
var screeningRepo service.ScreeningRepository
vault, err := secret.NewVault(c.SecretEncryptionKey)
if err != nil {
return err
@@ -123,6 +124,7 @@ func serve(ctx context.Context, c config.Config, logger *zap.Logger) error {
strategyRepo = repository.NewStrategyRepository(pool)
backtestRepo = repository.NewBacktestRepository(pool)
marketRepo = repository.NewMarketRepository(pool)
screeningRepo = repository.NewScreeningRepository(pool)
}
redisClient := redis.NewClient(&redis.Options{Addr: c.RedisAddr, Username: c.RedisUsername, Password: c.RedisPassword, DB: c.RedisDB, DialTimeout: time.Second, ReadTimeout: time.Second, WriteTimeout: time.Second, MaxRetries: -1, ContextTimeoutEnabled: true})
defer redisClient.Close()
@@ -133,6 +135,7 @@ func serve(ctx context.Context, c config.Config, logger *zap.Logger) error {
}
development := c.Environment == "local" || c.Environment == "test"
marketService := service.NewMarketService(marketRepo, providerRepo, market.New(), development)
screenings := service.NewScreeningService(screeningRepo, marketService, development)
notifications := service.NewNotificationService(notificationRepo, development)
backtests := service.NewBacktestService(backtestRepo, research.New(c.PythonExecutable), development, marketService)
workerContext, workerCancel := context.WithCancel(ctx)
@@ -142,8 +145,10 @@ func serve(ctx context.Context, c config.Config, logger *zap.Logger) error {
go func() { defer close(researchDone); backtests.Run(workerContext, logger) }()
marketDone := make(chan struct{})
go func() { defer close(marketDone); marketService.Run(workerContext, logger) }()
defer func() { workerCancel(); <-workerDone; <-researchDone; <-marketDone }()
identityOptions := handler.IdentityOptions{Market: marketService, Backtests: backtests, Strategies: service.NewStrategyService(strategyRepo, development), Notifications: notifications, Auth: auth, Fills: service.NewTradeFillService(fillRepo, development), Plans: service.NewTradePlanService(planRepo, development), Candidates: service.NewCandidateService(candidateRepo, development), Providers: service.NewProviderService(providerRepo, vault), Accounts: service.NewAccountService(accountRepo), Limiter: ratelimit.NewRedis(redisClient), DevelopmentLogin: development, SecureCookie: !development}
screeningDone := make(chan struct{})
go func() { defer close(screeningDone); screenings.Run(workerContext, logger) }()
defer func() { workerCancel(); <-workerDone; <-researchDone; <-marketDone; <-screeningDone }()
identityOptions := handler.IdentityOptions{Screenings: screenings, Market: marketService, Backtests: backtests, Strategies: service.NewStrategyService(strategyRepo, development), Notifications: notifications, Auth: auth, Fills: service.NewTradeFillService(fillRepo, development), Plans: service.NewTradePlanService(planRepo, development), Candidates: service.NewCandidateService(candidateRepo, development), Providers: service.NewProviderService(providerRepo, vault), Accounts: service.NewAccountService(accountRepo), Limiter: ratelimit.NewRedis(redisClient), DevelopmentLogin: development, SecureCookie: !development}
server := &http.Server{Addr: c.HTTPAddr, Handler: handler.NewRouter(health, logger, identityOptions), ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, IdleTimeout: 60 * time.Second, MaxHeaderBytes: 1 << 20}
result := make(chan error, 1)
go func() { result <- server.ListenAndServe() }()