Files
sanguo_vnpy/archive/2026-04-29-cleanup/test/backtest/download_510300_to_vnpy.py
T
2026-04-29 20:15:25 +08:00

255 lines
7.4 KiB
Python

#!/usr/bin/env python3
"""
下载 510300.SSE 数据并转换到vn.py数据库
使用赵云将军的AKShare-vnpy适配器
"""
import sys
import os
import sqlite3
from datetime import datetime
# 添加赵云的数据脚本路径
sys.path.insert(0, '/Users/chufeng/.openclaw/workspace-zhaoyun/sanguo_quant_live/zhaoyun-data/scripts/common_tools')
from akshare_vnpy_adapter import AKShareDataAdapter
def create_vnpy_database(db_path: str):
"""创建vn.py数据库结构"""
print(f"🔧 创建vn.py数据库: {db_path}")
os.makedirs(os.path.dirname(db_path), exist_ok=True)
# 如果数据库已存在,先删除
if os.path.exists(db_path):
os.remove(db_path)
print(" 删除旧数据库")
# 创建新数据库
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# 创建vn.py标准表结构
# dbbardata - K线数据表
cursor.execute("""
CREATE TABLE dbbardata (
symbol TEXT NOT NULL,
exchange TEXT,
interval TEXT NOT NULL,
datetime INTEGER NOT NULL,
open REAL NOT NULL,
high REAL NOT NULL,
low REAL NOT NULL,
close REAL NOT NULL,
volume INTEGER NOT NULL,
open_interest REAL,
turnover REAL,
PRIMARY KEY (symbol, interval, datetime)
);
""")
# 创建索引
cursor.execute("CREATE INDEX ix_dbbardata_symbol ON dbbardata(symbol);")
cursor.execute("CREATE INDEX ix_dbbardata_symbol_interval ON dbbardata(symbol, interval);")
cursor.execute("CREATE INDEX ix_dbbardata_datetime ON dbbardata(datetime);")
# dbtickdata - Tick数据表(暂时不需要)
cursor.execute("""
CREATE TABLE dbtickdata (
symbol TEXT NOT NULL,
exchange TEXT,
datetime INTEGER NOT NULL,
last_price REAL NOT NULL,
volume INTEGER NOT NULL,
turnover REAL NOT NULL,
open_interest REAL NOT NULL,
bid_price_1 REAL NOT NULL,
bid_volume_1 INTEGER NOT NULL,
ask_price_1 REAL NOT NULL,
ask_volume_1 INTEGER NOT NULL,
PRIMARY KEY (symbol, datetime)
);
""")
# sqlite_sequence表(sqlite自动维护)
conn.commit()
conn.close()
print("✅ 数据库结构创建完成")
return True
def download_510300_data():
"""下载510300.SSE数据"""
print("🚀 开始下载 510300.SSE (沪深300ETF) 日线数据...")
# 创建适配器
adapter = AKShareDataAdapter()
# 下载数据 - 最近10年
end_date = datetime.now().strftime('%Y%m%d')
start_date = '20160101'
print(f" 时间范围: {start_date} - {end_date}")
# 注意:AKShare中,需要YYYYMMDD格式
print(f" 使用日期格式: {start_date} - {end_date} (YYYYMMDD)")
# 注意:AKShare中,510300的代码是 510300,不需要后缀
try:
# 尝试获取指数数据
# 510300是ETF,使用股票数据接口
df = adapter.get_stock_daily(
symbol='510300',
start_date=start_date,
end_date=end_date
)
except Exception as e:
print(f" 使用股票接口失败: {e},尝试指数接口")
df = adapter.get_index_daily(
index_symbol='510300',
start_date=start_date.replace('%m%d', '').replace('%Y', '').replace('%d', ''),
end_date=end_date.replace('%Y%m%d', '')
)
if df.empty:
print("❌ 获取数据失败")
return None
print(f"✅ 获取数据成功: {len(df)}")
print("\n数据预览:")
print(df.head())
print("\n数据统计:")
print(df.describe())
return df
def import_to_vnpy_database(df, symbol: str, db_path: str):
"""导入数据到vn.py数据库"""
print(f"\n📥 导入数据到vn.py数据库...")
print(f" 标的: {symbol}")
print(f" 数据库: {db_path}")
# 连接数据库
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# 统计导入行数
imported = 0
# 遍历DataFrame并插入
for _, row in df.iterrows():
# 转换日期为unix时间戳(vn.py使用整数时间戳)
# AKShare返回的日期格式是字符串或datetime
date_val = row['date']
if hasattr(date_val, 'timestamp'):
# datetime对象
dt = date_val
else:
# 字符串,尝试解析
from datetime import datetime
try:
dt = datetime.strptime(str(date_val), '%Y-%m-%d')
except:
dt = datetime.strptime(str(date_val), '%Y%m%d')
timestamp = int(dt.timestamp())
# 插入数据
# vn.py标准dbbardata结构
cursor.execute("""
INSERT INTO dbbardata (
symbol, exchange, interval, datetime,
open, high, low, close, volume, turnover
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", (
symbol,
'SSE', # 交易所
'1d', # 日线
timestamp,
float(row['open']),
float(row['high']),
float(row['low']),
float(row['close']),
int(row.get('volume', 0)),
float(row.get('amount', row.get('volume', 0)))
))
imported += 1
# 提交
conn.commit()
# 验证
cursor.execute("SELECT COUNT(*) FROM dbbardata WHERE symbol = ?", (symbol,))
count = cursor.fetchone()[0]
conn.close()
print(f"✅ 导入完成: {imported}")
print(f" 验证: 数据库中共有 {count} 行数据")
return True
def main():
"""主函数"""
print("🚀 下载并导入 510300.SSE 数据到vn.py数据库")
print("="*60)
# 配置
symbol = "510300.SSE"
db_path = "/Users/chufeng/.openclaw/workspace-zhaoyun/zhaoyun-data/data/database_test.db"
print(f"目标标的: {symbol}")
print(f"目标数据库: {db_path}")
# 1. 创建数据库
if not create_vnpy_database(db_path):
print("❌ 创建数据库失败")
return False
# 2. 下载数据
df = download_510300_data()
if df is None or df.empty:
print("❌ 下载数据失败")
return False
# 3. 导入到数据库
if not import_to_vnpy_database(df, symbol, db_path):
print("❌ 导入数据失败")
return False
# 4. 验证结果
print("\n" + "="*60)
print("验证结果:")
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM dbbardata WHERE symbol = ?", (symbol,))
count = cursor.fetchone()[0]
cursor.execute("SELECT MIN(datetime), MAX(datetime) FROM dbbardata WHERE symbol = ?", (symbol,))
min_ts, max_ts = cursor.fetchone()
from datetime import datetime
min_dt = datetime.fromtimestamp(min_ts).strftime('%Y-%m-%d') if min_ts else 'N/A'
max_dt = datetime.fromtimestamp(max_ts).strftime('%Y-%m-%d') if max_ts else 'N/A'
conn.close()
print(f"✅ 标的 {symbol} 数据已成功导入")
print(f" 数据行数: {count}")
print(f" 时间范围: {min_dt} -> {max_dt}")
print("\n" + "="*60)
print("🎯 完成!")
print("下一步:")
print("1. 配置回测API使用这个数据库路径")
print("2. 重启API服务")
print("3. 关羽将军重新回测")
print("="*60)
return True
if __name__ == "__main__":
main()