与Gui库共同工作¶
某些情况下, 我们可能需要在一个 Python GUI 程序中使用TqSdk库. TqSdk 可以与Tkinter, PyQt, WxPython, PySimpleGui 等大多数常见 Python Gui 库配合工作.
下面以 PySimpleGui 为例, 介绍 Gui 库与 TqSdk 组合使用的方式.
先后使用GUI库和TqSdk¶
参见示例程序 param_input.py. 这个程序先使用 PySimpleGui 创建一个参数输入对话框, 用户输入参数后, 关闭对话框, 开始使用 TqSdk:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'limin'
"""
本程序演示如何为策略程序增加一个GUI参数输入框, 方便用户在运行策略前输入运行参数
"""
import PySimpleGUI as sg
from tqsdk import TqApi, TargetPosTask, TqAccount
from tqsdk.tafunc import ma
# 创建一个参数输入对话框
layout = [[sg.Text('交易账户')],
[sg.Text('期货公司'), sg.Input("快期模拟", key="broker_id")],
[sg.Text('账号'), sg.Input("111", key="user_id")],
[sg.Text('密码'), sg.Input("111", key="password")],
[sg.Text('策略参数')],
[sg.Text('合约代码'), sg.Input("SHFE.bu1912", key="symbol")],
[sg.Text('短周期'), sg.Input(30, key="short")],
[sg.Text('长周期'), sg.Input(60, key="long")],
[sg.OK(), sg.Cancel()]]
window = sg.Window('请输入策略运行参数', layout)
# 读取用户输入值
event, values = window.Read()
print(event, values)
window.close()
# 正常运行策略代码
SHORT = int(values["short"]) # 短周期
LONG = int(values["long"]) # 长周期
SYMBOL = values["symbol"]
api = TqApi(TqAccount(values["broker_id"], values["user_id"], values["password"]))
print("策略开始运行")
data_length = LONG + 2 # k线数据长度
klines = api.get_kline_serial(SYMBOL, duration_seconds=60, data_length=data_length)
target_pos = TargetPosTask(api, SYMBOL)
while True:
api.wait_update()
if api.is_changing(klines.iloc[-1], "datetime"): # 产生新k线:重新计算SMA
short_avg = ma(klines["close"], SHORT) # 短周期
long_avg = ma(klines["close"], LONG) # 长周期
# 均线下穿,做空
if long_avg.iloc[-2] < short_avg.iloc[-2] and long_avg.iloc[-1] > short_avg.iloc[-1]:
target_pos.set_target_volume(-3)
print("均线下穿,做空")
# 均线上穿,做多
if short_avg.iloc[-2] < long_avg.iloc[-2] and short_avg.iloc[-1] > long_avg.iloc[-1]:
target_pos.set_target_volume(3)
print("均线上穿,做多")
在两个线程中分别运行Gui和TqSdk¶
参见示例程序 multi_thread.py.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'limin'
import threading
import PySimpleGUI as sg
from tqsdk import TqApi, TargetPosTask
api = TqApi()
quote_a = api.get_quote("SHFE.rb1910")
quote_b = api.get_quote("SHFE.rb2001")
class WorkingThread(threading.Thread):
def run(self):
while True:
api.wait_update()
# 创建新线程
wt = WorkingThread()
wt.start()
layout = [[sg.Text('rb1910'), sg.Text("99999", key="rb1910.last")],
[sg.Text('rb2001'), sg.Text("99999", key="rb2001.last")],
[sg.Text('spread'), sg.Text("99999", key="spread")],
]
window = sg.Window('价差显示', layout)
while True: # Event Loop
event, values = window.Read(timeout=1)
if event is None or event == 'Exit':
break
window.Element('rb1910.last').Update(quote_a.last_price)
window.Element('rb2001.last').Update(quote_b.last_price)
window.Element('spread').Update(quote_b.last_price - quote_a.last_price)
window.Close()
在TqSdk任务中驱动Gui消息循环¶
参见示例程序 loop_integrate.py.
import asyncio
import sys
import PySimpleGUI as sg
from tqsdk import TqApi
loop = asyncio.get_event_loop()
api = TqApi(loop=loop)
quote_a = api.get_quote("SHFE.rb1910")
quote_b = api.get_quote("SHFE.rb2001")
async def gui_task():
layout = [[sg.Text('rb1910'), sg.Text("99999", key="rb1910.last")],
[sg.Text('rb2001'), sg.Text("99999", key="rb2001.last")],
[sg.Text('spread'), sg.Text("99999", key="spread")],
]
window = sg.Window('价差显示', layout)
while True:
event, values = window.Read(timeout=0)
if event is None or event == 'Exit':
sys.exit(0)
window.Element('rb1910.last').Update(quote_a.last_price)
window.Element('rb2001.last').Update(quote_b.last_price)
window.Element('spread').Update(quote_b.last_price - quote_a.last_price)
await asyncio.sleep(1) # 注意, 这里必须使用 asyncio.sleep, 不能用time.sleep
api.create_task(gui_task())
while True:
api.wait_update()