|
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
# 数据库初始化脚本
|
|
|
|
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
|
|
echo "========================================="
|
|
|
|
|
|
echo "期货股票数据平台 - 数据库初始化"
|
|
|
|
|
|
echo "========================================="
|
|
|
|
|
|
|
|
|
|
|
|
# 颜色定义
|
|
|
|
|
|
GREEN='\033[0;32m'
|
|
|
|
|
|
YELLOW='\033[1;33m'
|
|
|
|
|
|
RED='\033[0;31m'
|
|
|
|
|
|
NC='\033[0m' # No Color
|
|
|
|
|
|
|
|
|
|
|
|
# 检查 Docker 是否运行
|
|
|
|
|
|
if ! command -v docker &> /dev/null; then
|
|
|
|
|
|
echo -e "${RED}错误:Docker 未安装${NC}"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if ! docker info &> /dev/null; then
|
|
|
|
|
|
echo -e "${RED}错误:Docker 未运行${NC}"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
echo -e "${YELLOW}正在启动数据库服务...${NC}"
|
|
|
|
|
|
docker-compose up -d timescaledb redis
|
|
|
|
|
|
|
|
|
|
|
|
# 等待数据库就绪
|
|
|
|
|
|
echo -e "${YELLOW}等待 TimescaleDB 就绪...${NC}"
|
|
|
|
|
|
sleep 10
|
|
|
|
|
|
|
|
|
|
|
|
# 检查容器状态
|
|
|
|
|
|
if ! docker ps | grep -q kline_timescaledb; then
|
|
|
|
|
|
echo -e "${RED}错误:TimescaleDB 容器未启动${NC}"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
echo -e "${YELLOW}等待 Redis 就绪...${NC}"
|
|
|
|
|
|
sleep 5
|
|
|
|
|
|
|
|
|
|
|
|
if ! docker ps | grep -q kline_redis; then
|
|
|
|
|
|
echo -e "${RED}错误:Redis 容器未启动${NC}"
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# 初始化 TimescaleDB 表结构
|
|
|
|
|
|
echo -e "${YELLOW}初始化 TimescaleDB 表结构...${NC}"
|
|
|
|
|
|
|
|
|
|
|
|
docker exec kline_timescaledb psql -U postgres -d kline_data <<EOF
|
|
|
|
|
|
-- 创建 K 线数据表 (超表)
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS kline_data (
|
|
|
|
|
|
time TIMESTAMPTZ NOT NULL,
|
|
|
|
|
|
symbol VARCHAR(20) NOT NULL,
|
|
|
|
|
|
period VARCHAR(10) NOT NULL,
|
|
|
|
|
|
open NUMERIC(20, 8) NOT NULL,
|
|
|
|
|
|
high NUMERIC(20, 8) NOT NULL,
|
|
|
|
|
|
low NUMERIC(20, 8) NOT NULL,
|
|
|
|
|
|
close NUMERIC(20, 8) NOT NULL,
|
|
|
|
|
|
volume BIGINT NOT NULL,
|
|
|
|
|
|
amount NUMERIC(30, 8) DEFAULT 0,
|
|
|
|
|
|
open_interest BIGINT DEFAULT 0,
|
|
|
|
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
-- 转换为 hypertable
|
|
|
|
|
|
SELECT create_hypertable('kline_data', 'time', if_not_exists => TRUE);
|
|
|
|
|
|
|
|
|
|
|
|
-- 创建索引
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_kline_symbol_period
|
|
|
|
|
|
ON kline_data (symbol, period, time DESC);
|
|
|
|
|
|
|
|
|
|
|
|
-- 创建实时行情表
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS realtime_quotes (
|
|
|
|
|
|
time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
|
|
symbol VARCHAR(20) NOT NULL,
|
|
|
|
|
|
last_price NUMERIC(20, 8) NOT NULL,
|
|
|
|
|
|
open_price NUMERIC(20, 8),
|
|
|
|
|
|
high_price NUMERIC(20, 8),
|
|
|
|
|
|
low_price NUMERIC(20, 8),
|
|
|
|
|
|
prev_close NUMERIC(20, 8),
|
|
|
|
|
|
volume BIGINT,
|
|
|
|
|
|
amount NUMERIC(30, 8),
|
|
|
|
|
|
bid_price_1 NUMERIC(20, 8),
|
|
|
|
|
|
bid_volume_1 BIGINT,
|
|
|
|
|
|
ask_price_1 NUMERIC(20, 8),
|
|
|
|
|
|
ask_volume_1 BIGINT,
|
|
|
|
|
|
position BIGINT DEFAULT 0
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
-- 转换为 hypertable
|
|
|
|
|
|
SELECT create_hypertable('realtime_quotes', 'time', if_not_exists => TRUE);
|
|
|
|
|
|
|
|
|
|
|
|
-- 创建索引
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_realtime_symbol
|
|
|
|
|
|
ON realtime_quotes (symbol, time DESC);
|
|
|
|
|
|
EOF
|
|
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}✓ TimescaleDB 初始化完成${NC}"
|
|
|
|
|
|
|
|
|
|
|
|
# 插入测试数据
|
|
|
|
|
|
echo -e "${YELLOW}插入测试数据...${NC}"
|
|
|
|
|
|
|
|
|
|
|
|
docker exec kline_timescaledb psql -U postgres -d kline_data <<EOF
|
|
|
|
|
|
-- 插入测试 K 线数据 (最近 7 天的小时数据)
|
|
|
|
|
|
INSERT INTO kline_data (time, symbol, period, open, high, low, close, volume, amount)
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
now() - (interval '1 hour' * generate_series(0, 168)),
|
|
|
|
|
|
'IF2406',
|
|
|
|
|
|
'1h',
|
|
|
|
|
|
3500 + random() * 100,
|
|
|
|
|
|
3500 + random() * 120,
|
|
|
|
|
|
3500 - random() * 50,
|
|
|
|
|
|
3500 + random() * 80,
|
|
|
|
|
|
(random() * 10000)::bigint,
|
|
|
|
|
|
(random() * 1000000)::numeric
|
|
|
|
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
|
|
|
|
|
|
|
|
INSERT INTO kline_data (time, symbol, period, open, high, low, close, volume, amount)
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
now() - (interval '1 hour' * generate_series(0, 168)),
|
|
|
|
|
|
'IC2406',
|
|
|
|
|
|
'1h',
|
|
|
|
|
|
5800 + random() * 100,
|
|
|
|
|
|
5800 + random() * 120,
|
|
|
|
|
|
5800 - random() * 50,
|
|
|
|
|
|
5800 + random() * 80,
|
|
|
|
|
|
(random() * 8000)::bigint,
|
|
|
|
|
|
(random() * 800000)::numeric
|
|
|
|
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
|
|
EOF
|
|
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}✓ 测试数据插入完成${NC}"
|
|
|
|
|
|
|
|
|
|
|
|
# 启动后端服务
|
|
|
|
|
|
echo -e "${YELLOW}启动后端服务...${NC}"
|
|
|
|
|
|
docker-compose up -d backend
|
|
|
|
|
|
|
|
|
|
|
|
# 等待后端就绪
|
|
|
|
|
|
sleep 10
|
|
|
|
|
|
|
|
|
|
|
|
# 检查后端状态
|
|
|
|
|
|
if curl -s http://localhost:8000/health > /dev/null 2>&1; then
|
|
|
|
|
|
echo -e "${GREEN}✓ 后端服务启动成功${NC}"
|
|
|
|
|
|
else
|
|
|
|
|
|
echo -e "${YELLOW}警告:后端服务可能还未完全就绪${NC}"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# 启动前端服务
|
|
|
|
|
|
echo -e "${YELLOW}启动前端服务...${NC}"
|
|
|
|
|
|
docker-compose up -d frontend
|
|
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
echo -e "${GREEN}=========================================${NC}"
|
|
|
|
|
|
echo -e "${GREEN}数据库初始化完成!${NC}"
|
|
|
|
|
|
echo -e "${GREEN}=========================================${NC}"
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
echo "访问地址:"
|
|
|
|
|
|
echo " - 前端页面:http://localhost"
|
|
|
|
|
|
echo " - API 文档:http://localhost:8000/docs"
|
|
|
|
|
|
echo " - 健康检查:http://localhost:8000/health"
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
echo "默认管理员账号:"
|
|
|
|
|
|
echo " - 用户名:admin"
|
|
|
|
|
|
echo " - 密码:admin123 (首次登录请修改)"
|
|
|
|
|
|
echo ""
|