[增强功能]K线切片尝试修复bug,支持成交信号和自定义信号显示
This commit is contained in:
parent
62189748c2
commit
42e952b2cd
@ -1155,9 +1155,13 @@ class KLineWidget(KeyWraper):
|
|||||||
print(u'dataframe is None or Empty', file=sys.stderr)
|
print(u'dataframe is None or Empty', file=sys.stderr)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if 'datetime' in df_trades.columns:
|
||||||
|
col_datetime = 'datetime'
|
||||||
|
else:
|
||||||
|
col_datetime = 'time'
|
||||||
for idx in df_trades.index:
|
for idx in df_trades.index:
|
||||||
# 时间
|
# 时间
|
||||||
trade_time = df_trades['time'].loc[idx]
|
trade_time = df_trades[col_datetime].loc[idx]
|
||||||
if not isinstance(trade_time, datetime) and isinstance(trade_time, str):
|
if not isinstance(trade_time, datetime) and isinstance(trade_time, str):
|
||||||
trade_time = datetime.strptime(trade_time, '%Y-%m-%d %H:%M:%S')
|
trade_time = datetime.strptime(trade_time, '%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
@ -1415,41 +1419,71 @@ class KLineWidget(KeyWraper):
|
|||||||
|
|
||||||
|
|
||||||
class GridKline(QtWidgets.QWidget):
|
class GridKline(QtWidgets.QWidget):
|
||||||
"""多kline"""
|
"""多kline同时展示,时间联动"""
|
||||||
|
|
||||||
def __init__(self, parent=None, kline_settings={}, title=''):
|
def __init__(self, parent=None, kline_settings={}, title='', relocate=True):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
super(GridKline, self).__init__(parent)
|
super(GridKline, self).__init__(parent)
|
||||||
|
# widget的标题
|
||||||
if title:
|
if title:
|
||||||
self.setWindowTitle(title)
|
self.setWindowTitle(title)
|
||||||
|
|
||||||
self.kline_settings = kline_settings
|
self.canvas_1 = None
|
||||||
self.kline_names = list(self.kline_settings.keys())
|
self.canvas_2 = None
|
||||||
self.kline_dict = {}
|
self.canvas_3 = None
|
||||||
|
self.canvas_4 = None
|
||||||
|
self.canvas_5 = None
|
||||||
|
self.canvas_6 = None
|
||||||
|
self.canvas_7 = None
|
||||||
|
self.canvas_8 = None
|
||||||
|
|
||||||
|
# 每一个K线的设置
|
||||||
|
self.kline_settings = kline_settings
|
||||||
|
# K线名称
|
||||||
|
self.kline_names = list(self.kline_settings.keys())
|
||||||
|
# K线名称: K线图表
|
||||||
|
self.kline_dict = {}
|
||||||
|
#
|
||||||
self.grid_layout = QtWidgets.QGridLayout()
|
self.grid_layout = QtWidgets.QGridLayout()
|
||||||
self.setLayout(self.grid_layout)
|
self.setLayout(self.grid_layout)
|
||||||
|
|
||||||
|
self.relocate = relocate
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
""""""
|
"""初始化界面"""
|
||||||
|
|
||||||
|
id = 1
|
||||||
|
|
||||||
for kline_name, kline_setting in self.kline_settings.items():
|
for kline_name, kline_setting in self.kline_settings.items():
|
||||||
|
canvas = getattr(self, f'canvas_{id}')
|
||||||
|
if id > 8:
|
||||||
|
print(f'最多支持8个K线同时展现', file=sys.stderr)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 创建K线图表
|
||||||
canvas = KLineWidget(display_vol=False, display_sub=True)
|
canvas = KLineWidget(display_vol=False, display_sub=True)
|
||||||
canvas.show()
|
canvas.show()
|
||||||
|
# K线标题
|
||||||
canvas.KLtitle.setText(f'{kline_name}', size='18pt')
|
canvas.KLtitle.setText(f'{kline_name}', size='18pt')
|
||||||
canvas.title = f'{kline_name}'
|
canvas.title = f'{kline_name}'
|
||||||
|
# 主图指标
|
||||||
main_indicators = kline_setting.get('main_indicators', [])
|
main_indicators = kline_setting.get('main_indicators', [])
|
||||||
for main_indicator in main_indicators:
|
for main_indicator in main_indicators:
|
||||||
canvas.add_indicator(indicator=main_indicator, is_main=True)
|
canvas.add_indicator(indicator=main_indicator, is_main=True)
|
||||||
|
|
||||||
|
# 副图指标
|
||||||
sub_indicators = kline_setting.get('sub_indicators', [])
|
sub_indicators = kline_setting.get('sub_indicators', [])
|
||||||
for sub_indicator in sub_indicators:
|
for sub_indicator in sub_indicators:
|
||||||
canvas.add_indicator(indicator=sub_indicator, is_main=False)
|
canvas.add_indicator(indicator=sub_indicator, is_main=False)
|
||||||
|
|
||||||
self.kline_dict[kline_name] = canvas
|
self.kline_dict[kline_name] = canvas
|
||||||
# 注册重定向事件
|
|
||||||
canvas.relocate_notify_func = self.onRelocate
|
if self.relocate:
|
||||||
|
# 注册重定向事件
|
||||||
|
canvas.relocate_notify_func = self.onRelocate
|
||||||
|
|
||||||
|
id += 1
|
||||||
|
|
||||||
# 将所有Kline放到画板
|
# 将所有Kline放到画板
|
||||||
kline_names = list(self.kline_names)
|
kline_names = list(self.kline_names)
|
||||||
@ -1497,21 +1531,28 @@ class GridKline(QtWidgets.QWidget):
|
|||||||
sub_indicators=kline_setting.get('sub_indicators', [])
|
sub_indicators=kline_setting.get('sub_indicators', [])
|
||||||
)
|
)
|
||||||
|
|
||||||
# 加载交易信号
|
# 加载开、平仓的交易信号(一般是回测系统产生的)
|
||||||
trade_list_file = kline_setting.get('trade_list_file', None)
|
trade_list_file = kline_setting.get('trade_list_file', None)
|
||||||
if trade_list_file and os.path.exists(trade_list_file):
|
if trade_list_file and os.path.exists(trade_list_file):
|
||||||
print(f'loading {trade_list_file}')
|
print(f'loading {trade_list_file}')
|
||||||
df_trade = pd.read_csv(trade_list_file)
|
df_trade_list = pd.read_csv(trade_list_file)
|
||||||
self.kline_dict[kline_name].add_signals(df_trade)
|
self.kline_dict[kline_name].add_signals(df_trade_list)
|
||||||
|
|
||||||
# 加载tns
|
# 记载交易信号(实盘产生的)
|
||||||
|
trade_file = kline_setting.get('trade_file', None)
|
||||||
|
if trade_file and os.path.exists(trade_file):
|
||||||
|
print(f'loading {trade_file}')
|
||||||
|
df_trade = pd.read_csv(trade_file)
|
||||||
|
self.kline_dict[kline_name].add_trades(df_trade)
|
||||||
|
|
||||||
|
# 加载tns( 回测、实盘产生的)
|
||||||
tns_file = kline_setting.get('tns_file', None)
|
tns_file = kline_setting.get('tns_file', None)
|
||||||
if tns_file and os.path.exists(tns_file):
|
if tns_file and os.path.exists(tns_file):
|
||||||
print(f'loading {tns_file}')
|
print(f'loading {tns_file}')
|
||||||
df_tns = pd.read_csv(tns_file)
|
df_tns = pd.read_csv(tns_file)
|
||||||
self.kline_dict[kline_name].add_trans_df(df_tns)
|
self.kline_dict[kline_name].add_trans_df(df_tns)
|
||||||
|
|
||||||
# 加载policy 逻辑记录
|
# 加载policy 逻辑记录( 回测、实盘产生的)
|
||||||
dist_file = kline_setting.get('dist_file', None)
|
dist_file = kline_setting.get('dist_file', None)
|
||||||
if dist_file and os.path.exists(dist_file):
|
if dist_file and os.path.exists(dist_file):
|
||||||
print(f'loading {dist_file}')
|
print(f'loading {dist_file}')
|
||||||
@ -1546,6 +1587,196 @@ class GridKline(QtWidgets.QWidget):
|
|||||||
print(f'onRelocate exception:{str(ex)}')
|
print(f'onRelocate exception:{str(ex)}')
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
class MultiKlineWindow(QtWidgets.QMainWindow):
|
||||||
|
"""多窗口显示K线
|
||||||
|
包括:
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
def __init__(self, parent=None, kline_settings={}, title=''):
|
||||||
|
"""Constructor"""
|
||||||
|
super(MultiKlineWindow, self).__init__(parent)
|
||||||
|
|
||||||
|
# 每一个K线的设置
|
||||||
|
self.kline_settings = kline_settings
|
||||||
|
# K线名称
|
||||||
|
self.kline_names = list(self.kline_settings.keys())
|
||||||
|
# K线名称: K线图表
|
||||||
|
self.kline_dict = {}
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
|
||||||
|
# self.load_multi_kline()
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
def init_ui(self):
|
||||||
|
"""初始化界面"""
|
||||||
|
self.setWindowTitle(u'多周期')
|
||||||
|
self.maximumSize()
|
||||||
|
self.mdi = QtWidgets.QMdiArea()
|
||||||
|
self.setCentralWidget(self.mdi)
|
||||||
|
|
||||||
|
# 创建菜单
|
||||||
|
menubar = self.menuBar()
|
||||||
|
file_menu = menubar.addMenu("File")
|
||||||
|
file_menu.addAction("Cascade")
|
||||||
|
file_menu.addAction("Tiled")
|
||||||
|
file_menu.triggered[QtWidgets.QAction].connect(self.windowaction)
|
||||||
|
|
||||||
|
for kline_name, kline_setting in self.kline_settings.items():
|
||||||
|
|
||||||
|
sub_window = QtWidgets.QMdiSubWindow()
|
||||||
|
# K线标题
|
||||||
|
sub_window.setWindowTitle(kline_name)
|
||||||
|
|
||||||
|
# 创建K线图表
|
||||||
|
canvas = KLineWidget(display_vol=False, display_sub=True)
|
||||||
|
sub_window.setWidget(canvas)
|
||||||
|
canvas.show()
|
||||||
|
self.mdi.addSubWindow(sub_window)
|
||||||
|
|
||||||
|
# 主图指标
|
||||||
|
main_indicators = kline_setting.get('main_indicators', [])
|
||||||
|
for main_indicator in main_indicators:
|
||||||
|
canvas.add_indicator(indicator=main_indicator, is_main=True)
|
||||||
|
|
||||||
|
# 副图指标
|
||||||
|
sub_indicators = kline_setting.get('sub_indicators', [])
|
||||||
|
for sub_indicator in sub_indicators:
|
||||||
|
canvas.add_indicator(indicator=sub_indicator, is_main=False)
|
||||||
|
|
||||||
|
self.kline_dict[kline_name] = canvas
|
||||||
|
|
||||||
|
# 加载K线
|
||||||
|
if 'data_frame' in kline_setting:
|
||||||
|
df = kline_setting['data_frame']
|
||||||
|
else:
|
||||||
|
data_file = kline_setting.get('data_file', None)
|
||||||
|
if not data_file:
|
||||||
|
continue
|
||||||
|
df = pd.read_csv(data_file)
|
||||||
|
df = df.set_index(pd.DatetimeIndex(df['datetime']))
|
||||||
|
|
||||||
|
canvas.loadData(df,
|
||||||
|
main_indicators=kline_setting.get('main_indicators', []),
|
||||||
|
sub_indicators=kline_setting.get('sub_indicators', [])
|
||||||
|
)
|
||||||
|
|
||||||
|
# 加载开、平仓的交易信号(一般是回测系统产生的)
|
||||||
|
trade_list_file = kline_setting.get('trade_list_file', None)
|
||||||
|
if trade_list_file and os.path.exists(trade_list_file):
|
||||||
|
print(f'loading {trade_list_file}')
|
||||||
|
df_trade_list = pd.read_csv(trade_list_file)
|
||||||
|
self.kline_dict[kline_name].add_signals(df_trade_list)
|
||||||
|
|
||||||
|
# 记载交易信号(实盘产生的)
|
||||||
|
trade_file = kline_setting.get('trade_file', None)
|
||||||
|
if trade_file and os.path.exists(trade_file):
|
||||||
|
print(f'loading {trade_file}')
|
||||||
|
df_trade = pd.read_csv(trade_file)
|
||||||
|
self.kline_dict[kline_name].add_trades(df_trade)
|
||||||
|
|
||||||
|
# 加载tns( 回测、实盘产生的)
|
||||||
|
tns_file = kline_setting.get('tns_file', None)
|
||||||
|
if tns_file and os.path.exists(tns_file):
|
||||||
|
print(f'loading {tns_file}')
|
||||||
|
df_tns = pd.read_csv(tns_file)
|
||||||
|
self.kline_dict[kline_name].add_trans_df(df_tns)
|
||||||
|
|
||||||
|
# 加载policy 逻辑记录( 回测、实盘产生的)
|
||||||
|
dist_file = kline_setting.get('dist_file', None)
|
||||||
|
if dist_file and os.path.exists(dist_file):
|
||||||
|
print(f'loading {dist_file}')
|
||||||
|
df_markup = pd.read_csv(dist_file)
|
||||||
|
df_markup = df_markup[['datetime', 'price', 'operation']]
|
||||||
|
df_markup.rename(columns={'operation': 'markup'}, inplace=True)
|
||||||
|
self.kline_dict[kline_name].add_markups(df_markup=df_markup,
|
||||||
|
include_list=kline_setting.get('dist_include_list', []),
|
||||||
|
exclude_list=['buy', 'short', 'sell', 'cover'])
|
||||||
|
|
||||||
|
sub_window.show()
|
||||||
|
|
||||||
|
self.mdi.cascadeSubWindows()
|
||||||
|
|
||||||
|
def windowaction(self,q):
|
||||||
|
if q.text() == "cascade":
|
||||||
|
self.mdi.cascadeSubWindows()
|
||||||
|
|
||||||
|
if q.text() == "Cascade":
|
||||||
|
self.mdi.tileSubWindows()
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
def load_multi_kline(self):
|
||||||
|
"""加载多周期窗口"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
for kline_name, kline_setting in self.kline_settings.items():
|
||||||
|
|
||||||
|
canvas = self.kline_dict.get(kline_name, None)
|
||||||
|
if canvas is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 加载K线
|
||||||
|
if 'data_frame' in kline_setting:
|
||||||
|
df = kline_setting['data_frame']
|
||||||
|
else:
|
||||||
|
data_file = kline_setting.get('data_file', None)
|
||||||
|
if not data_file:
|
||||||
|
continue
|
||||||
|
df = pd.read_csv(data_file)
|
||||||
|
df = df.set_index(pd.DatetimeIndex(df['datetime']))
|
||||||
|
|
||||||
|
canvas.loadData(df,
|
||||||
|
main_indicators=kline_setting.get('main_indicators', []),
|
||||||
|
sub_indicators=kline_setting.get('sub_indicators', [])
|
||||||
|
)
|
||||||
|
|
||||||
|
# 加载开、平仓的交易信号(一般是回测系统产生的)
|
||||||
|
trade_list_file = kline_setting.get('trade_list_file', None)
|
||||||
|
if trade_list_file and os.path.exists(trade_list_file):
|
||||||
|
print(f'loading {trade_list_file}')
|
||||||
|
df_trade_list = pd.read_csv(trade_list_file)
|
||||||
|
self.kline_dict[kline_name].add_signals(df_trade_list)
|
||||||
|
|
||||||
|
# 记载交易信号(实盘产生的)
|
||||||
|
trade_file = kline_setting.get('trade_file', None)
|
||||||
|
if trade_file and os.path.exists(trade_file):
|
||||||
|
print(f'loading {trade_file}')
|
||||||
|
df_trade = pd.read_csv(trade_file)
|
||||||
|
self.kline_dict[kline_name].add_trades(df_trade)
|
||||||
|
|
||||||
|
# 加载tns( 回测、实盘产生的)
|
||||||
|
tns_file = kline_setting.get('tns_file', None)
|
||||||
|
if tns_file and os.path.exists(tns_file):
|
||||||
|
print(f'loading {tns_file}')
|
||||||
|
df_tns = pd.read_csv(tns_file)
|
||||||
|
self.kline_dict[kline_name].add_trans_df(df_tns)
|
||||||
|
|
||||||
|
# 加载policy 逻辑记录( 回测、实盘产生的)
|
||||||
|
dist_file = kline_setting.get('dist_file', None)
|
||||||
|
if dist_file and os.path.exists(dist_file):
|
||||||
|
print(f'loading {dist_file}')
|
||||||
|
df_markup = pd.read_csv(dist_file)
|
||||||
|
df_markup = df_markup[['datetime', 'price', 'operation']]
|
||||||
|
df_markup.rename(columns={'operation': 'markup'}, inplace=True)
|
||||||
|
self.kline_dict[kline_name].add_markups(df_markup=df_markup,
|
||||||
|
include_list=kline_setting.get('dist_include_list', []),
|
||||||
|
exclude_list=['buy', 'short', 'sell', 'cover'])
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
traceback.print_exc()
|
||||||
|
QtWidgets.QMessageBox.warning(self, 'Exception', u'Load data Exception',
|
||||||
|
QtWidgets.QMessageBox.Cancel,
|
||||||
|
QtWidgets.QMessageBox.NoButton)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
"""关闭窗口时的事件"""
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
def display_multi_grid(kline_settings={}):
|
def display_multi_grid(kline_settings={}):
|
||||||
"""显示多图"""
|
"""显示多图"""
|
||||||
from vnpy.trader.ui import create_qapp
|
from vnpy.trader.ui import create_qapp
|
||||||
|
@ -15,21 +15,36 @@ import pandas as pd
|
|||||||
from vnpy.trader.ui.kline.crosshair import Crosshair
|
from vnpy.trader.ui.kline.crosshair import Crosshair
|
||||||
from vnpy.trader.ui.kline.kline import *
|
from vnpy.trader.ui.kline.kline import *
|
||||||
|
|
||||||
|
|
||||||
class UiSnapshot(object):
|
class UiSnapshot(object):
|
||||||
"""查看切片"""
|
"""查看切片"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def show(self, snapshot_file: str, d=None):
|
def show(self, snapshot_file: str,
|
||||||
|
d: dict = None,
|
||||||
|
trade_file: str = "",
|
||||||
|
tns_file: str = "",
|
||||||
|
dist_file: str = "",
|
||||||
|
dist_include_list=[],
|
||||||
|
use_grid=True):
|
||||||
|
"""
|
||||||
|
显示切片
|
||||||
|
:param snapshot_file: 切片文件路径(通过这个方法,可读取历史切片)
|
||||||
|
:param d: 切片数据(用于实时查看)
|
||||||
|
:param trade_file: 实盘成交文件
|
||||||
|
:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
if d is None:
|
if d is None:
|
||||||
if not os.path.exists(snapshot_file):
|
if not os.path.exists(snapshot_file):
|
||||||
print(f'{snapshot_file}不存在', file=sys.stderr)
|
print(f'{snapshot_file}不存在', file=sys.stderr)
|
||||||
return
|
return
|
||||||
|
|
||||||
with bz2.BZ2File(snapshot_file, 'rb') as f:
|
with bz2.BZ2File(snapshot_file, 'rb') as f:
|
||||||
d = pickle.load(f)
|
d = pickle.load(f)
|
||||||
|
|
||||||
use_zlib = d.get('zlib', False)
|
use_zlib = d.get('zlib', False)
|
||||||
klines = d.pop('klines', None)
|
klines = d.pop('klines', None)
|
||||||
@ -53,20 +68,33 @@ class UiSnapshot(object):
|
|||||||
df = pd.DataFrame(data_list)
|
df = pd.DataFrame(data_list)
|
||||||
df = df.set_index(pd.DatetimeIndex(df['datetime']))
|
df = df.set_index(pd.DatetimeIndex(df['datetime']))
|
||||||
|
|
||||||
|
setting = {
|
||||||
|
"data_frame": df,
|
||||||
|
"main_indicators": [x.get('name') for x in main_indicators],
|
||||||
|
"sub_indicators": [x.get('name') for x in sub_indicators]
|
||||||
|
}
|
||||||
|
if len(trade_file) > 0 and os.path.exists(trade_file):
|
||||||
|
setting.update({"trade_file": trade_file})
|
||||||
|
|
||||||
|
if len(tns_file) > 0 and os.path.exists(tns_file):
|
||||||
|
setting.update({"tns_file": tns_file})
|
||||||
|
|
||||||
|
if len(dist_file) > 0 and os.path.exists((dist_file)) and len(dist_include_list) > 0:
|
||||||
|
setting.update({"dist_file": dist_file, "dist_include_list": dist_include_list})
|
||||||
|
|
||||||
kline_settings.update(
|
kline_settings.update(
|
||||||
{
|
{
|
||||||
k:
|
k: setting
|
||||||
{
|
|
||||||
"data_frame": df,
|
|
||||||
"main_indicators": [x.get('name') for x in main_indicators],
|
|
||||||
"sub_indicators": [x.get('name') for x in sub_indicators]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# K线界面
|
# K线界面
|
||||||
try:
|
try:
|
||||||
w = GridKline(kline_settings=kline_settings, title=d.get('strategy',''))
|
if use_grid:
|
||||||
w.showMaximized()
|
w = GridKline(kline_settings=kline_settings, title=d.get('strategy', ''), relocate=True)
|
||||||
|
w.showMaximized()
|
||||||
|
else:
|
||||||
|
w = MultiKlineWindow(kline_settings=kline_settings, title=d.get('strategy', ''))
|
||||||
|
w.showMaximized()
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print(u'exception:{},trace:{}'.format(str(ex), traceback.format_exc()))
|
print(u'exception:{},trace:{}'.format(str(ex), traceback.format_exc()))
|
||||||
|
@ -1036,7 +1036,7 @@ class ContractManager(QtWidgets.QWidget):
|
|||||||
"""
|
"""
|
||||||
Show contracts by symbol
|
Show contracts by symbol
|
||||||
"""
|
"""
|
||||||
flt = str(self.filter_line.text())
|
flt = str(self.filter_line.text()).lower()
|
||||||
|
|
||||||
all_contracts = self.main_engine.get_all_contracts()
|
all_contracts = self.main_engine.get_all_contracts()
|
||||||
if flt:
|
if flt:
|
||||||
|
Loading…
Reference in New Issue
Block a user