refactor: migrate API keys to config, extend Kline intervals, add DB extensions

Security:
- Move hardcoded Binance API key/secret from rest.ts to env.yaml (exchange config segment)
- Add ExchangeConfig validation in config/validators.ts
- Export typed exchange config from config/index.ts
- Update AGENTS/07-caveats.md to reflect the new policy

Kline intervals (add 3m / 2h / 6h / 8h / 1mon):
- TypeScript: update KlineInterval type, KLINE_INTERVAL_MS mapping, build_aggregates_sql refresh chain
- Python: sync KlineInterval Literal type, INTERVAL_TO_TABLE and INTERVAL_MS mappings, db_test table list
- SQL: add 5 continuous aggregate materialized views (klines_3m/2h/6h/8h/1mon) with indexes
- SQL: extend default kline_intervals in trading_pairs table
- SQL: add cross-sectional query indexes for klines_1d and klines_1w

DB:
- Enable pg_prewarm extension (backtest warmup)
- Enable pg_stat_statements extension (slow query monitoring)

Other:
- data/run/exchange.ts: graceful pgsql shutdown after backfill completes
- Config path: load from data/env.yaml (symlink) instead of project root
This commit is contained in:
Rekey
2026-06-14 18:45:01 +08:00
parent a9c45cce39
commit 9351dec226
15 changed files with 311 additions and 27 deletions
+34
View File
@@ -15,6 +15,7 @@
export interface EnvConfig {
db: DbConfig;
redis: RedisConfig;
exchange: ExchangeConfig;
logging: LoggingConfig;
}
@@ -31,6 +32,18 @@ export interface RedisConfig {
publish_enabled: boolean;
}
/** 交易所 API 密钥配置(按交易所 ID 索引) */
export interface ExchangeConfig {
binance: ExchangeApiKeys;
// 未来扩展:okx、bybit 等
[exchangeId: string]: ExchangeApiKeys | undefined;
}
export interface ExchangeApiKeys {
api_key: string;
api_secret: string;
}
export interface LoggingConfig {
level: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
node_env: "development" | "production" | "test";
@@ -77,6 +90,21 @@ export function validateConfig(raw: unknown): EnvConfig {
const redisUrl = assertString(redisObj["url"], "redis.url");
const redisPublishEnabled = assertBoolean(redisObj["publish_enabled"], "redis.publish_enabled");
// --- exchange ---
const exchange = obj["exchange"];
if (typeof exchange !== "object" || exchange === null) {
throw new Error("[config] env.yaml 缺少 exchange 配置段");
}
const exObj = exchange as Record<string, unknown>;
const binance = exObj["binance"];
if (typeof binance !== "object" || binance === null) {
throw new Error("[config] env.yaml exchange 缺少 binance 配置");
}
const binanceObj = binance as Record<string, unknown>;
const binanceApiKey = assertString(binanceObj["api_key"], "exchange.binance.api_key");
const binanceApiSecret = assertString(binanceObj["api_secret"], "exchange.binance.api_secret");
// --- logging ---
const logging = obj["logging"];
if (typeof logging !== "object" || logging === null) {
@@ -99,6 +127,12 @@ export function validateConfig(raw: unknown): EnvConfig {
url: redisUrl,
publish_enabled: redisPublishEnabled,
},
exchange: {
binance: {
api_key: binanceApiKey,
api_secret: binanceApiSecret,
},
},
logging: {
level: logLevel,
node_env: nodeEnv,