补充已退市合约数据和数据库同步功能
- 拉取 FG2601-FG2607 已退市合约的完整日线行情 - 新增 SQLite 入库逻辑,支持 daily 和 contracts 两张表 - 更新 README 数据字典和数据库说明 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import csv
|
||||
import os
|
||||
import sqlite3
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
@@ -8,6 +9,7 @@ import requests
|
||||
TOKEN = "76efd8465f9f2591aa42a385268e06acf6b80b7a15be2267ad2281b7"
|
||||
API_URL = "https://api.tushare.pro"
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
|
||||
DB_PATH = os.path.join(os.path.dirname(__file__), "db", "futures.db")
|
||||
|
||||
FUT_DAILY_FIELDS = [
|
||||
"ts_code", "trade_date", "pre_close", "pre_settle",
|
||||
@@ -46,6 +48,15 @@ def get_active_contracts(exchange, fut_code):
|
||||
return [c for c in contracts if not c.get("delist_date") or c["delist_date"] > today]
|
||||
|
||||
|
||||
def get_all_contracts(exchange, fut_code):
|
||||
"""获取指定交易所、品种的全部合约(含已退市)"""
|
||||
return tushare_query(
|
||||
"fut_basic",
|
||||
params={"exchange": exchange, "fut_code": fut_code, "fut_type": "1"},
|
||||
fields="ts_code,symbol,name,list_date,delist_date",
|
||||
)
|
||||
|
||||
|
||||
def save_contract_csv(fut_code, contracts):
|
||||
"""对每个活跃合约拉取日线行情并写入 data/{fut_code}/{code}.csv"""
|
||||
out_dir = os.path.join(DATA_DIR, fut_code)
|
||||
@@ -77,9 +88,98 @@ def save_contract_csv(fut_code, contracts):
|
||||
time.sleep(0.3) # tushare 频率限制
|
||||
|
||||
|
||||
def init_db():
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS daily (
|
||||
ts_code TEXT NOT NULL,
|
||||
trade_date TEXT NOT NULL,
|
||||
pre_close REAL,
|
||||
pre_settle REAL,
|
||||
open REAL,
|
||||
high REAL,
|
||||
low REAL,
|
||||
close REAL,
|
||||
settle REAL,
|
||||
change1 REAL,
|
||||
change2 REAL,
|
||||
vol REAL,
|
||||
amount REAL,
|
||||
oi REAL,
|
||||
oi_chg REAL,
|
||||
delv_settle REAL,
|
||||
PRIMARY KEY (ts_code, trade_date)
|
||||
)
|
||||
""")
|
||||
conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS contracts (
|
||||
ts_code TEXT PRIMARY KEY,
|
||||
symbol TEXT,
|
||||
name TEXT,
|
||||
exchange TEXT,
|
||||
fut_code TEXT,
|
||||
list_date TEXT,
|
||||
delist_date TEXT
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def sync_contracts_to_db(fut_code, exchange, contracts):
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
for c in contracts:
|
||||
cursor.execute(
|
||||
"INSERT OR REPLACE INTO contracts (ts_code, symbol, name, exchange, fut_code, list_date, delist_date) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
(c["ts_code"], c["symbol"], c["name"], exchange, fut_code, c["list_date"], c.get("delist_date")),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print(f" contracts 表写入 {len(contracts)} 条")
|
||||
|
||||
|
||||
def sync_csv_to_db():
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
|
||||
for root, _, files in os.walk(DATA_DIR):
|
||||
for fname in sorted(files):
|
||||
if not fname.endswith(".csv"):
|
||||
continue
|
||||
|
||||
fpath = os.path.join(root, fname)
|
||||
with open(fpath) as f:
|
||||
reader = csv.DictReader(f)
|
||||
rows = list(reader)
|
||||
|
||||
if not rows:
|
||||
continue
|
||||
|
||||
placeholders = ",".join("?" for _ in FUT_DAILY_FIELDS)
|
||||
cols = ",".join(FUT_DAILY_FIELDS)
|
||||
sql = f"INSERT OR REPLACE INTO daily ({cols}) VALUES ({placeholders})"
|
||||
vals = [[r.get(c) for c in FUT_DAILY_FIELDS] for r in rows]
|
||||
cursor.executemany(sql, vals)
|
||||
|
||||
print(f" {fname:12s} {len(rows)} 条 -> daily 表")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
contracts = get_active_contracts("CZCE", "FG")
|
||||
print(f"活跃玻璃合约共 {len(contracts)} 个:")
|
||||
# 活跃合约
|
||||
active = get_active_contracts("CZCE", "FG")
|
||||
# 已退市合约:FG2601-FG2607
|
||||
extra_codes = {f"FG{suffix}.ZCE" for suffix in [f"26{i:02d}" for i in range(1, 8)]}
|
||||
all_fg = get_all_contracts("CZCE", "FG")
|
||||
active_codes = {c["ts_code"] for c in active}
|
||||
extra = [c for c in all_fg if c["ts_code"] in extra_codes and c["ts_code"] not in active_codes]
|
||||
contracts = active + extra
|
||||
|
||||
print(f"玻璃合约共 {len(contracts)} 个(含 {len(extra)} 个已退市):")
|
||||
|
||||
for c in contracts:
|
||||
code = c["ts_code"].split(".")[0]
|
||||
@@ -87,4 +187,9 @@ if __name__ == "__main__":
|
||||
|
||||
print("\n拉取日线行情...")
|
||||
save_contract_csv("FG", contracts)
|
||||
|
||||
print("\n写入数据库...")
|
||||
init_db()
|
||||
sync_contracts_to_db("FG", "CZCE", contracts)
|
||||
sync_csv_to_db()
|
||||
print("完成")
|
||||
|
||||
Reference in New Issue
Block a user