Skip to content

Commit

Permalink
修改了一大波文件,发布支持 web_gui 版本
Browse files Browse the repository at this point in the history
  • Loading branch information
shinny-mayanqiong committed Dec 17, 2019
1 parent d920a00 commit 2c461ea
Show file tree
Hide file tree
Showing 17 changed files with 212 additions and 204 deletions.
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,7 @@ def get_tag(self):
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
],
package_data={
"tqsdk": ["web"]
}
)
53 changes: 30 additions & 23 deletions tqsdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class TqApi(object):
DEFAULT_INS_URL = "https://openmd.shinnytech.com/t/md/symbols/latest.json"

def __init__(self, account: Union['TqAccount', TqSim, 'TqApi', None] = None, url: Optional[str] = None,
backtest: Optional[TqBacktest] = None, debug: Optional[str] = None,
loop: Optional[asyncio.AbstractEventLoop] = None, _ins_url=None, _md_url=None, _td_url=None, web_gui=False, _http_server_port=None) -> None:
backtest: Optional[TqBacktest] = None, web_gui: bool = False, debug: Optional[str] = None,
loop: Optional[asyncio.AbstractEventLoop] = None, _ins_url=None, _md_url=None, _td_url=None) -> None:
"""
创建天勤接口实例
Expand Down Expand Up @@ -87,25 +87,33 @@ def __init__(self, account: Union['TqAccount', TqSim, 'TqApi', None] = None, url
* 为了图形化界面能够接收到程序传输的数据并且刷新,在程序中,需要循环调用 api.wait_update的形式去更新和获取数据
* 推荐打开图形化界面的浏览器为Google Chrome 或 Firefox
Example::
Example1::
# 使用实盘帐号直连行情和交易服务器
from tqsdk import TqApi, TqAccount
api = TqApi(TqAccount("H海通期货", "022631", "123456"))
Example2::
# 使用模拟帐号直连行情服务器
from tqsdk import TqApi, TqSim
api = TqApi(TqSim()) # 不填写参数则默认为 TqSim() 模拟账号
Example3::
# 进行策略回测
from datetime import date
from tqsdk import TqApi, TqSim, TqBacktest
api = TqApi(TqSim(), backtest=TqBacktest(start_dt=date(2018, 5, 1), end_dt=date(2018, 10, 1)))
Example4::
# 开启 web_gui 功能
from tqsdk import TqApi
api = TqApi(web_gui=True)
"""

# 记录参数
if account is None:
account = TqSim()
Expand All @@ -126,10 +134,8 @@ def __init__(self, account: Union['TqAccount', TqSim, 'TqApi', None] = None, url
if _td_url:
self._td_url = _td_url
self._loop = asyncio.SelectorEventLoop() if loop is None else loop # 创建一个新的 ioloop, 避免和其他框架/环境产生干扰
self._tq_web_helper = TqWebHelper(_http_server_port=_http_server_port, enabled_web_gui=web_gui)

# 初始化 logger

self._logger = logging.getLogger("TqApi")
self._logger.setLevel(logging.DEBUG)
if not self._logger.handlers:
Expand Down Expand Up @@ -183,8 +189,10 @@ def __init__(self, account: Union['TqAccount', TqSim, 'TqApi', None] = None, url
self._master._slaves.append(self)
self._account = self._master._account
self._to_tq = self._master._to_tq
self._web_gui = False # 如果是slave, _web_gui 一定是 False
return # 注: 如果是slave,则初始化到这里结束并返回,以下代码不执行

self._web_gui = web_gui
# 初始化
if sys.platform.startswith("win"):
self.create_task(self._windows_patch()) # Windows系统下asyncio不支持KeyboardInterrupt的临时补丁
Expand Down Expand Up @@ -1129,11 +1137,10 @@ def _setup_connection(self):
self._account._run(self, self._send_chan, self._recv_chan, ws_md_send_chan, ws_md_recv_chan,
ws_td_send_chan, ws_td_recv_chan))

# 与web配合, 行情和交易都要 对接到 backtest 上
if self._tq_web_helper:
web_send_chan, web_recv_chan = TqChan(self), TqChan(self)
self.create_task(self._tq_web_helper._run(self, web_send_chan, web_recv_chan, self._send_chan, self._recv_chan))
self._send_chan, self._recv_chan = web_send_chan, web_recv_chan
# 与 web 配合, 在 tq_web_helper 内部中处理 web_gui 选项
web_send_chan, web_recv_chan = TqChan(self), TqChan(self)
self.create_task(TqWebHelper()._run(self, web_send_chan, web_recv_chan, self._send_chan, self._recv_chan))
self._send_chan, self._recv_chan = web_send_chan, web_recv_chan

# 抄送部分数据包到天勤
if tq_send_chan and tq_recv_chan:
Expand Down Expand Up @@ -1451,7 +1458,7 @@ def _process_chart_data_for_web(self, serial, symbol, duration, col, count, righ
"color": int(data.get(".color", [0xFFFF0000])[-1]),
"width": int(data.get(".width", [1])[-1]),
"board": data.get(".board", ["MAIN"])[-1]
})
}, aid="set_web_chart_data")
elif data_type == "KSERIAL":
send_data = {}
range_left = right - count
Expand All @@ -1468,11 +1475,11 @@ def _process_chart_data_for_web(self, serial, symbol, duration, col, count, righ
"range_left": right - count,
"range_right": right - 1,
"board": data.get(".board", ["MAIN"])[-1]
})
}, aid="set_web_chart_data")

def _send_series_data(self, symbol, duration, serial_id, serial_data):
def _send_series_data(self, symbol, duration, serial_id, serial_data, aid="set_chart_data"):
pack = {
"aid": "set_chart_data",
"aid": aid,
"symbol": symbol,
"dur_nano": duration,
"datas": {
Expand Down Expand Up @@ -1551,8 +1558,7 @@ async def _connect(self, url, send_chan, recv_chan):
}) as client:
# 发送网络连接建立的通知,code = 2019112901
notify_id = uuid.UUID(int=TqApi.RD.getrandbits(128)).hex
notify = {}
notify[notify_id] = {
notify = {
"type": "MESSAGE",
"level": "INFO",
"code": 2019112901,
Expand All @@ -1561,6 +1567,8 @@ async def _connect(self, url, send_chan, recv_chan):
}

if not first_connect: # 如果不是第一次连接, 即为重连
# 发送网络连接重新建立的通知,code = 2019112902
notify["code"] = 2019112902
notify["level"] = "WARNING"
notify["content"] = "与 %s 的网络连接已恢复" % url
un_processed = True # 重连后数据未处理完
Expand All @@ -1570,10 +1578,10 @@ async def _connect(self, url, send_chan, recv_chan):
if url == self._md_url: # 获取重连时需发送的所有 set_chart 指令包
set_chart_packs = {k: v for k, v in resend_request.items() if v.get("aid") == "set_chart"}

# 发送网络连接建立的通知,code = 2019112901,这里区分了第一次连接和重连
# 发送网络连接建立的通知,code = 2019112901 or 2019112902,这里区分了第一次连接和重连
await recv_chan.send({
"aid": "rtn_data",
"data": [{"notify": notify}]
"data": [{"notify": {notify_id: notify}}]
})
send_task = self.create_task(
self._send_handler(client, url, resend_request, send_chan, first_connect))
Expand Down Expand Up @@ -1682,19 +1690,18 @@ async def _connect(self, url, send_chan, recv_chan):
# 希望做到的效果是遇到网络问题可以断线重连, 但是可能抛出的例外太多了(TimeoutError,socket.gaierror等), 又没有文档或工具可以理出 try 代码中所有可能遇到的例外
# 而这里的 except 又需要处理所有子函数及子函数的子函数等等可能抛出的例外, 因此这里只能遇到问题之后再补, 并且无法避免 false positive 和 false negative
except (websockets.exceptions.ConnectionClosed, OSError):
# 发送网络连接断开的通知,code = 2019112902
# 发送网络连接断开的通知,code = 2019112911
notify_id = uuid.UUID(int=TqApi.RD.getrandbits(128)).hex
notify = {}
notify[notify_id] = {
notify = {
"type": "MESSAGE",
"level": "WARNING",
"code": 2019112902,
"code": 2019112911,
"content": "与 %s 的网络连接断开,请检查客户端及网络是否正常" % url,
"url": url
}
await recv_chan.send({
"aid": "rtn_data",
"data": [{"notify": notify}]
"data": [{"notify": {notify_id: notify}}]
})
finally:
if first_connect:
Expand Down
2 changes: 1 addition & 1 deletion tqsdk/backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ async def _send_diff(self):
if not self._serials: # 当无可发送数据时则抛出BacktestFinished例外,包括未订阅任何行情 或 所有已订阅行情的最后一笔行情获取完成
self._logger.warning("回测结束")
if self._current_dt < self._end_dt:
self._current_dt = 150000000000000000000 # 一个远大于 end_dt 的日期
self._current_dt = 2145888000000000000 # 一个远大于 end_dt 的日期 20380101
await self._sim_recv_chan.send({
"aid": "rtn_data",
"data": [{
Expand Down
5 changes: 2 additions & 3 deletions tqsdk/demo/tutorial/backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
__author__ = 'chengzhi'

from datetime import date
from contextlib import closing
from tqsdk import TqApi, TqSim, TqBacktest, TargetPosTask
from tqsdk import TqApi, TqBacktest, TargetPosTask

'''
如果当前价格大于5分钟K线的MA15则开多仓
如果小于则平仓
回测从 2018-05-01 到 2018-10-01
'''
# 在创建 api 实例时传入 TqBacktest 就会进入回测模式
api = TqApi(TqSim(init_balance=100000), backtest=TqBacktest(start_dt=date(2018, 5, 2), end_dt=date(2018, 5, 5)))
api = TqApi(backtest=TqBacktest(start_dt=date(2018, 5, 1), end_dt=date(2018, 10, 1)))
# 获得 m1901 5分钟K线的引用
klines = api.get_kline_serial("DCE.m1901", 5 * 60, data_length=15)
# 创建 m1901 的目标持仓 task,该 task 负责调整 m1901 的仓位到指定的目标仓位
Expand Down
2 changes: 2 additions & 0 deletions tqsdk/demo/tutorial/t10.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'chengzhi'

from tqsdk import TqApi

# 创建API实例.
Expand Down
14 changes: 5 additions & 9 deletions tqsdk/demo/tutorial/t90.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,15 @@

'''
画图示例: 在主图中画指标线
注意:1 画图功能仅在天勤终端/天勤Vscode插件中生效,请在这两个平台中运行画图相关的代码
2 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
注意: 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
'''

api = TqApi(web_gui=True)
api = TqApi(web_gui=True) # web_gui=True, 开启使用 web 界面查看绘图结果的功能
klines = api.get_kline_serial("SHFE.au2006", 5)

ma = MA(klines, 30) # 使用tqsdk自带指标函数计算均线
klines["ma_MAIN"] = ma.ma
# 在主图中画一根默认颜色(红色)的ma指标线
ma = MA(klines, 30) # 使用 tqsdk 自带指标函数计算均线
klines["ma_MAIN"] = ma.ma # 在主图中画一根默认颜色(红色)的 ma 指标线

# 由于需要在浏览器中查看绘图结果,因此程序不能退出
while True:
api.wait_update()
if api.is_changing(klines):
ma = MA(klines, 30) # 使用tqsdk自带指标函数计算均线
klines["ma_MAIN"] = ma.ma
26 changes: 13 additions & 13 deletions tqsdk/demo/tutorial/t91.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@

'''
画图示例: 在附图中画指标线
注意:1 画图功能仅在天勤终端/天勤Vscode插件中生效,请在这两个平台中运行画图相关的代码
2 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
注意: 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
'''

api = TqApi(web_gui=True)
api = TqApi(web_gui=True) # web_gui=True, 开启使用 web 界面查看绘图结果的功能
klines = api.get_kline_serial("SHFE.au1910", 24 * 60 * 60)
ma = MA(klines, 30) # 使用tqsdk自带指标函数计算均线

while True:
# 示例: 在附图中画一根绿色的ma指标线
klines["ma_B2"] = ma.ma
klines["ma_B2.board"] = "B2" # 设置附图: 可以设置任意字符串,同一字符串表示同一副图
klines["ma_B2.color"] = 0xFF00FF00 # 设置为绿色
# 示例: 在附图中画一根绿色的ma指标线
klines["ma_B2"] = ma.ma
klines["ma_B2.board"] = "B2" # 设置附图: 可以设置任意字符串,同一字符串表示同一副图
klines["ma_B2.color"] = 0xFF00FF00 # 设置为绿色

# 示例: 在另一个附图画一根比ma小4的宽度为4的紫色指标线
klines["ma_4"] = ma.ma - 4
klines["ma_4.board"] = "MA4" # 设置为另一个附图
klines["ma_4.color"] = 0xFF9933CC # 设置为紫色
klines["ma_4.width"] = 4 # 设置宽度为4,默认为1
# 示例: 在另一个附图画一根比ma小4的宽度为4的紫色指标线
klines["ma_4"] = ma.ma - 4
klines["ma_4.board"] = "MA4" # 设置为另一个附图
klines["ma_4.color"] = 0xFF9933CC # 设置为紫色
klines["ma_4.width"] = 4 # 设置宽度为4,默认为1

# 由于需要在浏览器中查看绘图结果,因此程序不能退出
while True:
api.wait_update()
20 changes: 12 additions & 8 deletions tqsdk/demo/tutorial/t92.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@

'''
画图示例: 在主图中画信号线及文字标注
注意:1 画图功能仅在天勤终端/天勤Vscode插件中生效,请在这两个平台中运行画图相关的代码
2 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
注意: 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
'''

api = TqApi(web_gui=True)
klines = api.get_kline_serial("SHFE.au2002", 60)
api = TqApi(web_gui=True) # web_gui=True, 开启使用 web 界面查看绘图结果的功能
klines = api.get_kline_serial("SHFE.au2002", 300)

# 在主图中最后一根K线上画射线以标注需要的信号
api.draw_line(klines, -1, klines.iloc[-1].close, -1, klines.iloc[-1].high, line_type="RAY", color=0xFFFF9900, width=3)
# 绘制字符串
api.draw_text(klines, "信号1", x=-1, y=klines.iloc[-1].high + 5, color=0xFFFF3333)
# 给主图最后5根K线加一个方框
api.draw_box(klines, x1=-5, y1=klines.iloc[-5]["high"], x2=-1, y2=klines.iloc[-1]["low"], width=1, color=0xFF0000FF,
bg_color=0x7000FF00)

# 由于需要在浏览器中查看绘图结果,因此程序不能退出
while True:
# 在主图中最后一根K线上画射线以标注需要的信号
api.draw_line(klines, -1, klines.iloc[-1].close, -1, klines.iloc[-1].high, id="my_line", line_type="RAY", color=0xFFFF9900, width=3)
# 绘制字符串
api.draw_text(klines, "信号1", x=-1, y=klines.iloc[-1].high + 5, id="my_text", color=0xFFFF3333)
api.wait_update()
24 changes: 14 additions & 10 deletions tqsdk/demo/tutorial/t93.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@

'''
画图示例: 在主图中画线和方框
注意:1 画图功能仅在天勤终端/天勤Vscode插件中生效,请在这两个平台中运行画图相关的代码
2 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
注意: 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
'''

api = TqApi(web_gui=True)
klines = api.get_kline_serial("SHFE.cu1910", 86400)
api = TqApi(web_gui=True) # web_gui=True, 开启使用 web 界面查看绘图结果的功能
klines = api.get_kline_serial("SHFE.au2002", 60)

# 由于需要在浏览器中查看绘图结果,因此程序不能退出
while True:
# 在主图中画直线
api.draw_line(klines, -4, klines.iloc[-4].low, -3, klines.iloc[-3].high, line_type="LINE", color=0xFF0000FF)
# 给主图最后5根K线加一个方框
api.draw_box(klines, x1=-5, y1=klines.iloc[-5]["high"], x2=-1, y2=klines.iloc[-1]["low"], width=1, color=0xFF0000FF,
bg_color=0x7000FF00)
api.wait_update()
api.wait_update() # 当有业务信息发生变化时执行
# 当最后 1 根柱子最大最小值价差大于 0.05 时,在主图绘制信号
high = klines.iloc[-1].high
low = klines.iloc[-1].low
if high - low > 0.05:
# 绘制直线, 每一个 id 对应同一条直线
api.draw_line(klines, -1, high, -1, low, id="box%.0f" % (klines.iloc[-1].id), color=0xaa662244, width=4)
# 绘制字符串
api.draw_text(klines, "信号1", x=-1, y=low, id="text%.0f" % (klines.iloc[-1].id), color=0xFFFF3333)

17 changes: 9 additions & 8 deletions tqsdk/demo/tutorial/t94.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@

'''
画图示例: 在附图中画K线
注意:1 画图功能仅在天勤终端/天勤Vscode插件中生效,请在这两个平台中运行画图相关的代码
2 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
注意: 画图示例中用到的数据不含有实际意义,请根据自己的实际策略情况进行修改
'''

api = TqApi(web_gui=True)

klines = api.get_kline_serial("SHFE.cu1910", 86400)
klines2 = api.get_kline_serial("SHFE.cu1911", 86400)

# 在附图画出 cu1911 的K线: 需要将open、high、log、close的数据都设置正确
klines["cu1911.open"] = klines2["open"]
klines["cu1911.high"] = klines2["high"]
klines["cu1911.low"] = klines2["low"]
klines["cu1911.close"] = klines2["close"]
klines["cu1911.board"] = "B2"

# 由于需要在浏览器中查看绘图结果,因此程序不能退出
while True:
# 在附图画出 cu1911 的K线: 需要将open、high、log、close的数据都设置正确
klines["cu1911.open"] = klines2["open"]
klines["cu1911.high"] = klines2["high"]
klines["cu1911.low"] = klines2["low"]
klines["cu1911.close"] = klines2["close"]
klines["cu1911.board"] = "B2"
api.wait_update()
Loading

0 comments on commit 2c461ea

Please sign in to comment.