Files
WarrenZhou e28bfec957 Initial commit: 可转债轮动分析系统
- 实时行情:东财push2主源 + 腾讯批量报价备用源(自动切换)
- 历史K线:东财push2his主源 + 腾讯web子域备用源(含熔断机制)
- 增量同步:支持 -incr/-since 参数按存档日期增量入库
- 策略回测:净值曲线/10指标/基准对比,含基本面过滤
- 用户认证:用户名密码 + 邮箱验证码双登录方式
- 前端:三Tab SPA(实时行情/策略回测/数据管理)
2026-08-17 20:23:22 +08:00

102 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// fundamentals 是正股基本面数据入库命令:
//
// go run ./cmd/fundamentals [-db 库路径]
//
// 从 convert_bond 表读取所有正股代码,通过东财 clist 接口批量拉取
// 基本面数据(ROE/资产负债率/净利润/ST状态),写入 stock_fundamental 表。
package main
import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
"time"
"stock-analysis/internal/datasource/eastmoney"
"stock-analysis/internal/storage/sqlite"
)
func main() {
dbPath := flag.String("db", defaultDBPath(), "SQLite 数据库文件路径")
flag.Parse()
store, err := sqlite.Open(*dbPath)
if err != nil {
fatal("打开数据库失败: ", err)
}
defer store.Close()
ctx := context.Background()
// 1. 获取所有正股代码。
stock2bond, err := store.GetStockBondMap(ctx)
if err != nil {
fatal("获取正股映射失败: ", err)
}
if len(stock2bond) == 0 {
fmt.Println("convert_bond 表为空,请先执行 go run ./cmd/ingest -all 入库转债数据")
return
}
stockCodes := make([]string, 0, len(stock2bond))
for code := range stock2bond {
stockCodes = append(stockCodes, code)
}
fmt.Printf("正股数量:%d\n", len(stockCodes))
// 2. 分批拉取基本面数据(每批最多 200 只)。
client := eastmoney.NewClient()
const batchSize = 200
var totalSaved, totalFail int
for i := 0; i < len(stockCodes); i += batchSize {
end := i + batchSize
if end > len(stockCodes) {
end = len(stockCodes)
}
batch := stockCodes[i:end]
funds, err := client.FetchStockFundamentals(ctx, batch)
if err != nil {
fmt.Printf("批次 %d-%d 拉取失败: %v\n", i, end-1, err)
totalFail += len(batch)
continue
}
for _, f := range funds {
f.UpdateDate = time.Now().Format("2006-01-02")
if err := store.SaveStockFundamental(ctx, f); err != nil {
fmt.Printf(" %s %s: 保存失败 %v\n", f.Code, f.Name, err)
totalFail++
continue
}
totalSaved++
}
fmt.Printf("批次 %d-%d: 拉取 %d 只, 已保存 %d\n", i+1, end, len(batch), totalSaved)
// 控制请求频率。
if end < len(stockCodes) {
time.Sleep(2 * time.Second)
}
}
fmt.Printf("\n基本面入库完成:成功 %d 只,失败 %d 只(库: %s)\n", totalSaved, totalFail, *dbPath)
}
// defaultDBPath 返回默认数据库路径。
func defaultDBPath() string {
local := os.Getenv("LOCALAPPDATA")
if local == "" {
local = os.TempDir()
}
return filepath.Join(local, "stock-analysis", "stock.db")
}
// fatal 打印错误并退出。
func fatal(msg string, err error) {
fmt.Fprintln(os.Stderr, msg, err)
os.Exit(1)
}