天勤量化

安装

1
2
3
pip3 install tqsdk -U
# 或
pip3 install tqsdk -U -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host=pypi.tuna.tsinghua.edu.cn

初始化

1
2
from tqsdk import TqApi, TqAuth
api = TqApi(auth=TqAuth("账户", "密码"))

获取K线数据

1
2
3
# 获取大连商品交易所铁矿石2309合约(DCE.i2309)的分钟K线数据
# data_length:获取K线数据的数量,默认值:200
klines = api.get_kline_serial("DCE.i2309", 60, data_length=15)

回测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'Paul Ding'

# https://doc.shinnytech.com/tqsdk/latest/demo/base.html#backtest
from datetime import date
from tqsdk import TqApi, TqAuth, TqBacktest, TargetPosTask

'''
如果当前价格大于5分钟K线的MA15则开多仓
如果小于则平仓
回测从 2023-05-01 到 2023-06-01
'''
# 在创建 api 实例时传入 TqBacktest 就会进入回测模式
api = TqApi(backtest=TqBacktest(start_dt=date(2023, 5, 1), end_dt=date(2023, 6, 1)),
auth=TqAuth("账户", "密码"))
# 获得 i2309 5分钟K线的引用
klines = api.get_kline_serial("DCE.i2309", 5 * 60, data_length=15)
# 创建 i2309 的目标持仓 task,该 task 负责调整 i2309 的仓位到指定的目标仓位
target_pos = TargetPosTask(api, "DCE.i2309")

while True:
api.wait_update()
if api.is_changing(klines):
ma = sum(klines.close.iloc[-15:]) / 15
print("最新价", klines.close.iloc[-1], "MA", ma)
if klines.close.iloc[-1] > ma:
print("最新价大于MA: 目标多头5手")
# 设置目标持仓为多头5手
target_pos.set_target_volume(5)
elif klines.close.iloc[-1] < ma:
print("最新价小于MA: 目标空仓")
# 设置目标持仓为空仓
target_pos.set_target_volume(0)

下载数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'Paul Ding'

# https://doc.shinnytech.com/tqsdk/latest/demo/base.html#downloader
# id: 1234 (k线序列号)
# datetime: 1501080715000000000 (K线起点时间(按北京时间),自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数)
# open: 51450.0 (K线起始时刻的最新价)
# high: 51450.0 (K线时间范围内的最高价)
# low: 51450.0 (K线时间范围内的最低价)
# close: 51450.0 (K线结束时刻的最新价)
# volume: 11 (K线时间范围内的成交量)
# open_oi: 27354 (K线起始时刻的持仓量)
# close_oi: 27355 (K线结束时刻的持仓量)

# 上海期货交易所:SHFE
# 大连商品交易所:DCE
# 郑州商品交易所:CZCE

# 上海期货交易所:SHFE
# 黄金:au
# 白银:ag
# 铜:au
# 铝:al
# 锌:zn
# 螺纹钢:rb

# 大连商品交易所:DCE
# 铁矿石:i
# 焦炭:j
# 焦煤:jm

import sys
import os
from datetime import datetime
from contextlib import closing
from tqsdk import TqApi, TqAuth
from tqsdk.tools import DataDownloader

symbols = ["DCE.i", "DCE.j", "DCE.jm", "SHFE.rb", "SHFE.au",
"SHFE.ag", "SHFE.cu", "SHFE.al", "SHFE.zn", "SHFE.ni"]
years = range(20, 25, 1) # not include the second number.
months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]
dur_seconds = [("m01", 60), ("m03", 60 * 3), ("m05", 60 * 5), ("m10", 60 * 10),
("m15", 60 * 15), ("m30", 60 * 30),
("h1", 3600), ("h2", 3600 * 2), ("h3", 3600 * 3), ("h4", 3600 * 4),
("d1", 3600 * 24), ("d7", 3600 * 24 * 7)]
contracts = ["{}{}{}".format(symbol, year, month) for symbol in symbols
for year in years for month in months]

if not os.path.exists("csv"): os.mkdir("csv")
os.chdir("csv")
for contract in contracts:
print(contract)
try:
api = TqApi(auth=TqAuth("账户", "密码"))
with closing(api):
for dur_sec in dur_seconds:
csv_file_name = "{}_{}.csv".format(contract, dur_sec[0])
print(csv_file_name)
kd = DataDownloader(api, symbol_list=contract, dur_sec=dur_sec[1],
start_dt=datetime(2015, 1, 1, 0, 0, 0),
end_dt=datetime(2024, 12, 31, 23, 0, 0),
csv_file_name="{}".format(csv_file_name))
while not kd.is_finished():
api.wait_update()
print("progress: %s: %.2f%%" % (csv_file_name, kd.get_progress()))
except KeyboardInterrupt:
sys.exit("用户中断程序执行 ...")
except Exception as err:
print(err, contract)

策略一(双均线策略)

金叉买入,死叉卖出

上升通道:

均线金叉:MA5>MA10

MACD线金叉:

MACD(12, 26, 9):diff > dea

1
2
3
4
5
6
7
8
9
>'''
>flag[0]: 1: 买入; 0: 持有; -1: 卖出
>flag[1]: MA3 - MA7
>flag[2]: ma5[k] - ma5[k-5]
>flag[3]: macd.diff - macd.dea
>flag[4]: macd.diff[k] - macd.diff[k-5]

>flag[1] & flag[2] & flag[3] & flag[4]
>'''