新增玻璃期货日线数据拉取功能
- 通过 Tushare HTTP API 获取活跃合约列表和日线行情 - 数据按品种分文件夹存储为 CSV - 添加 README 项目说明和字段文档 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import csv
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
|
||||
TOKEN = "76efd8465f9f2591aa42a385268e06acf6b80b7a15be2267ad2281b7"
|
||||
API_URL = "https://api.tushare.pro"
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
|
||||
|
||||
FUT_DAILY_FIELDS = [
|
||||
"ts_code", "trade_date", "pre_close", "pre_settle",
|
||||
"open", "high", "low", "close", "settle",
|
||||
"change1", "change2", "vol", "amount", "oi", "oi_chg",
|
||||
"delv_settle",
|
||||
]
|
||||
|
||||
|
||||
def tushare_query(api_name, params=None, fields=None):
|
||||
req = {"api_name": api_name, "token": TOKEN}
|
||||
if params:
|
||||
req["params"] = params
|
||||
if fields:
|
||||
req["fields"] = fields
|
||||
|
||||
resp = requests.post(API_URL, json=req)
|
||||
data = resp.json()
|
||||
|
||||
if data["code"] != 0:
|
||||
raise Exception(f"API error ({data['code']}): {data['msg']}")
|
||||
|
||||
fields_list = data["data"]["fields"]
|
||||
items = data["data"]["items"]
|
||||
return [dict(zip(fields_list, item)) for item in items]
|
||||
|
||||
|
||||
def get_active_contracts(exchange, fut_code):
|
||||
"""获取指定交易所、品种仍在交易的合约列表"""
|
||||
contracts = tushare_query(
|
||||
"fut_basic",
|
||||
params={"exchange": exchange, "fut_code": fut_code, "fut_type": "1"},
|
||||
fields="ts_code,symbol,name,list_date,delist_date",
|
||||
)
|
||||
today = datetime.now().strftime("%Y%m%d")
|
||||
return [c for c in contracts if not c.get("delist_date") or c["delist_date"] > today]
|
||||
|
||||
|
||||
def save_contract_csv(fut_code, contracts):
|
||||
"""对每个活跃合约拉取日线行情并写入 data/{fut_code}/{code}.csv"""
|
||||
out_dir = os.path.join(DATA_DIR, fut_code)
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
for c in contracts:
|
||||
ts_code = c["ts_code"] # e.g. FG2609.ZCE
|
||||
csv_name = ts_code.split(".")[0] + ".csv" # FG2609.csv
|
||||
csv_path = os.path.join(out_dir, csv_name)
|
||||
|
||||
rows = tushare_query(
|
||||
"fut_daily",
|
||||
params={"ts_code": ts_code},
|
||||
fields=",".join(FUT_DAILY_FIELDS),
|
||||
)
|
||||
if not rows:
|
||||
print(f" {csv_name:12s} 无数据,跳过")
|
||||
continue
|
||||
|
||||
rows.sort(key=lambda r: r["trade_date"])
|
||||
|
||||
with open(csv_path, "w", newline="") as f:
|
||||
w = csv.DictWriter(f, fieldnames=FUT_DAILY_FIELDS)
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
|
||||
print(f" {csv_name:12s} {len(rows)} 条记录 ({rows[0]['trade_date']} ~ {rows[-1]['trade_date']})")
|
||||
|
||||
time.sleep(0.3) # tushare 频率限制
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
contracts = get_active_contracts("CZCE", "FG")
|
||||
print(f"活跃玻璃合约共 {len(contracts)} 个:")
|
||||
|
||||
for c in contracts:
|
||||
code = c["ts_code"].split(".")[0]
|
||||
print(f" {code:8s} 上市:{c['list_date']} 退市:{c.get('delist_date','-')}")
|
||||
|
||||
print("\n拉取日线行情...")
|
||||
save_contract_csv("FG", contracts)
|
||||
print("完成")
|
||||
Reference in New Issue
Block a user