import numpy as np
import statsmodels.tsa.stattools as st
from tqsdk import TqApi, TqAuth, TargetPosTask
api = TqApi(web_gui=True, auth=TqAuth("arthas", "yq7013836"))
rb_labels = ["SHFE.rb2401", "SHFE.rb2405", "SHFE.rb2410"] # 螺纹钢合约列表
hc_labels = ["SHFE.hc2401", "SHFE.hc2405", "SHFE.hc2410"] # 热卷合约列表
def find_cointegrated_pair(rb_list, hc_list, api):
min_pvalue = 1.0
best_pair = (None, None)
# 同时获取RB和HC的K线数据
for rb in rb_list:
for hc in hc_list:
k_rb = api.get_kline_serial(rb, 60*15, data_length=2000)
k_hc = api.get_kline_serial(hc, 60*15, data_length=2000)
# 确保数据长度一致
min_length = min(len(k_rb['close']), len(k_hc['close']))
close_rb = k_rb['close'][-min_length:]
close_hc = k_hc['close'][-min_length:]
# 协整检验
score, pvalue, _ = st.coint(close_rb, close_hc)
if pvalue < min_pvalue:
min_pvalue = pvalue
best_pair = (rb, hc, close_rb, close_hc)
return best_pair if min_pvalue < 0.05 else (None, None, None, None) # 设置5%显著性水平
symbol_rb, symbol_hc, close_rb, close_hc = find_cointegrated_pair(rb_labels, hc_labels, api)
# 计算价差统计量
spread = close_rb - close_hc
mean_spread = np.mean(spread)
std_spread = np.std(spread)
# 设置交易阈值
ENTRY_THRESHOLD = 1.5 # 1.5个标准差
EXIT_THRESHOLD = 0.5 # 0.5个标准差
target_rb = TargetPosTask(api, symbol_rb)
target_hc = TargetPosTask(api, symbol_hc)
while True:
api.wait_update()
current_rb = api.get_quote(symbol_rb).last_price
current_hc = api.get_quote(symbol_hc).last_price
current_spread = current_rb - current_hc
# 计算Z-score
z_score = (current_spread - mean_spread) / std_spread
# 获取当前仓位
pos_rb = api.get_position(symbol_rb)
pos_hc = api.get_position(symbol_hc)
# 交易逻辑
if not (pos_rb.pos or pos_hc.pos): # 无持仓时
if z_score > ENTRY_THRESHOLD:
# 做空价差:卖RB/买HC
target_rb.set_target_volume(-10)
target_hc.set_target_volume(10)
elif z_score < -ENTRY_THRESHOLD:
# 做多价差:买RB/卖HC
target_rb.set_target_volume(10)
target_hc.set_target_volume(-10)
else: # 有持仓时
if abs(z_score) < EXIT_THRESHOLD:
target_rb.set_target_volume(0)
target_hc.set_target_volume(0)
# 动态更新价差统计量(每100根K线)
if len(close_rb) % 100 == 0:
spread = close_rb[-1000:] - close_hc[-1000:] # 滚动窗口
mean_spread = np.mean(spread)
std_spread = np.std(spread)
api.close()